如何根据子查询中的特定值过滤记录?

时间:2016-12-08 06:45:17

标签: mysql sql database join query-optimization

情境: 我有一张我想要的工作表。每个作业都有一个或多个与之关联的项目,这些项目存储在jobItems表中。 item的代码和详细信息保存在items表中。作业和jobItems表之间存在一对多关系。另外请记住,它有大数据集。

我想在其jobItems中显示所有具有一个特定项目的作业。

MySQL小提琴: http://sqlfiddle.com/#!9/4a5a47

架构:

CREATE TABLE jobs (
    `id` INT,
    `jobRef` VARCHAR (55)
);

INSERT INTO jobs (`id`, `jobRef`)
VALUES
    (1, 'job1'),
    (2, 'job2'),
    (3, 'job3');

CREATE TABLE jobItems (
    `id` INT,
    `itemId` INT,
    `jobId` INT
);

INSERT INTO jobItems (`id`, `itemId`, `jobId`)
VALUES
    (1, 1, 1),
    (2, 2, 1),
    (3, 3, 1),
    (4, 1, 2),
    (5, 2, 2),
    (6, 3, 3);

CREATE TABLE items (
    `id` INT,
    `itemCode` VARCHAR (55)
);

INSERT INTO items (`id`, `itemCode`)
VALUES
    (1, 'item1'),
    (2, 'item2'),
    (3, 'item3');

查询:

SELECT
    jobs.*, ji.allItems
FROM
    jobs
LEFT JOIN (
    SELECT
        jobItems.jobId,
        GROUP_CONCAT(items.itemCode) AS allItems
    FROM
        jobItems
    INNER JOIN items ON jobItems.itemId = items.id
    GROUP BY
        jobItems.jobId
) AS ji ON ji.jobId = jobs.id

正如您所注意到的,在jobItems.jobId上有一个LEFT JOIN和GROUP BY,它们在实现基于项目的作业过滤器时会产生问题。

尝试选项:

  • 我尝试删除GROUP BY和GROUP_CONCAT,因此它将返回 所有可能的工作项组合。我想要操纵它们 在后端使用php。但它有一个缺点,它扰乱了 分页。
  • 我还试图将LEFT JOIN动态更改为INNER JOIN和 在子查询中,我在INNER JOIN INNER JOIN中添加了一个条件 项目ON jobItems.itemId = items.id AND jobItems.itemId IN(1)但是, 由于GROUP BY,它无法获取所需的结果 仅返回只有一个具有给定itemId的项目的作业。 它不会返回包含项目的多个项目的作业 itemId = 1。

简而言之,我想获取所有包含itemId = 1项目的作业。预期结果是job1和job2,因为它们都包含item1。

2 个答案:

答案 0 :(得分:2)

试试这个

SELECT jobs.*, ji.allItems
FROM jobs
INNER JOIN (
    SELECT
        jobItems.jobId,
        GROUP_CONCAT(items.itemCode) AS allItems
    FROM
        jobItems
    INNER JOIN items ON jobItems.itemId = items.id 
    GROUP BY
        jobItems.jobId
    HAVING MAX(CASE WHEN jobItems.itemId = 1 THEN 1 ELSE 0 END) > 0
) AS ji ON ji.jobId = jobs.id

SQLFiddle

对于多个项目过滤器(例如,您想要查找与项目1和2相关联的作业)

SELECT jobs.*, ji.allItems
FROM jobs
INNER JOIN (
    SELECT
        jobItems.jobId,
        GROUP_CONCAT(items.itemCode) AS allItems
    FROM
        jobItems
    INNER JOIN items ON jobItems.itemId = items.id 
    GROUP BY
        jobItems.jobId
    HAVING 
    MAX(CASE WHEN jobItems.itemId = 1 THEN 1 ELSE 0 END) > 0 AND
    MAX(CASE WHEN jobItems.itemId = 2 THEN 1 ELSE 0 END) > 0 
) AS ji ON ji.jobId = jobs.id

答案 1 :(得分:0)

这对你有用吗?

select j.*, i.itemCode from jobs j
inner join jobItems m on m.jobid = j.id
inner join items i on i.id = m.itemId
where exists (select 'x' from jobItems a 
              where a.itemId = 2
              and a.jobId = j.id)

希望你想获得特定项目绑定的工作。

让我知道我是否想念您的要求。

http://sqlfiddle.com/#!9/4a5a47/11