【问题标题】:How to filter records based on specific value in subquery?如何根据子查询中的特定值过滤记录?
【发布时间】:2017-04-23 08:04:16
【问题描述】:

场景: 我有一张要获取的工作表。每个作业都有一个或多个与之关联的项目,这些项目存储在 jobItems 表中。项目的代码和详细信息保存在项目表中。 jobs 和 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 上添加了一个条件 items ON jobItems.itemId = items.id AND jobItems.itemId IN (1) 但是, 由于 GROUP BY,它不会获取所需的结果 只返回只有一项具有给定 itemId 的作业。 它不会返回具有多个项目的作业,包括项目 itemId= 1。

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

【问题讨论】:

  • 您的预期结果是什么?
  • @Madhivanan 我已经编辑了问题并在其中添加了预期结果。
  • job3 有 item1,仅供参考
  • Job3 也有 item1
  • @TimBiegeleisen ,对不起,我已经编辑了作业 3 并更正了它的项目。

标签: mysql sql database join query-optimization


【解决方案1】:

试试这个

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

【讨论】:

  • 如果最小值 itemId 恰好小于 1,这将不起作用。
  • 是的。我修改不同
  • 它的工作。我们可以将其转换为像 IN 条件一样一次过滤多个项目吗?
【解决方案2】:

这适合你吗?

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

【讨论】:

  • 我还需要显示与作业相关的所有项目,它不会获取。
  • 我做了一些改变。请检查并让我知道这项工作适合你
  • 它多次返回工作。每项1次
  • 抱歉,我误解了您的要求。当用户选择 item2 进行限制时,我可以告诉我结果吗?
  • 它应该返回两行: (1) job1 item2,item3,item1 (2) job2 item2,item1`
猜你喜欢
  • 1970-01-01
  • 2020-03-17
  • 1970-01-01
  • 1970-01-01
  • 2021-09-30
  • 1970-01-01
  • 2018-08-17
  • 1970-01-01
  • 2016-04-05
相关资源
最近更新 更多