【问题标题】:Exclude records from results if other records referencing them are linked to a specific value如果引用它们的其他记录链接到特定值,则从结果中排除记录
【发布时间】:2019-05-25 01:07:44
【问题描述】:

这是我想要完成的:

我必须参考四个表来获取我要查找的数据。列表、部分、列表项和标签分配。

  • 列表表包含代表每个列表的记录
  • listitem 表引用 list.id 并代表每个列表中的所有项目
  • 零件表包含所有零件,每个零件都有一个唯一的 id
  • labelassign 表具有友好标签(如标签),其中引用了 partId 以标记部件。

视觉:

列表

id  name
--  ----
1   part1
2   part2
3   part3
4   part4

列表项

id  partId  listId
--  ----    ------
1   10      1
2   11      1
3   12      1
4   13      2
5   14      2

部分

id  name
--  ----
1   part1
2   part2
3   part3
4   part4
10  part10
11  part11
12  part12
13  part13
14  part14

标签分配

id  label          partId
--  -----          ----
1   StandardParts  1
2   StandardParts  2
3   SmallParts     3
4   LargeParts     4
5   HugeParts      5
6   MediumParts    10
7   MediumParts    11
8   MediumParts    12
9   SmallParts     13
10  MediumParts    14

获取具有特定标签的所有列表:

SELECT list.name
FROM list
INNER JOIN part ON list.name = part.name
INNER JOIN labelassign ON part.id = labelassign.partId AND labelassign.label LIKE '%StandardParts%'
# Using LIKE for '%StandardParts%' because there are variations in the real data but I want them all

如果 list.name 记录没有 StandardParts 标签,则应将它们从结果中排除。

第二部分比较棘手,我遇到了麻烦。

每个list 记录都有许多listitem 记录,它们代表该列表中的项目。所有带有 StandardParts 标签的 list 记录都应该至少有一个带有 SmallParts 标签的 listitem 记录,但不是所有的都有,没有的都是我想找到什么。

listitem 记录通过其listitem.listId 字段被称为属于特定列表。因此,对于每个list,我想检查它的任何listitems 是否有 SmallParts 作为标签(通过检查匹配部分和该部分的标签,如上所示),并且如果没有那些listitems 我希望父list 记录保留在结果集中。否则,list.name 应从结果中排除。

根据@Eric Brandt 的初步回答,这是我目前所拥有的:

SELECT DISTINCT
    l.id,
    l.num
FROM
    list AS l
INNER JOIN
    part AS p1
        ON b.num = p1.num
# Without this up here I didn't get the filtration, lists without the StandardParts label were included in results
INNER JOIN
    labelassign AS la
        ON p1.id = la.partId
        AND la.label LIKE '%StandardParts%'
INNER JOIN
    listitem AS li
        ON l.id = li.listId
INNER JOIN
    part AS p
        ON li.partId = p.id
WHERE
    EXISTS
        (
            SELECT 1
            FROM
                labelassign AS la1
            WHERE
                la1.partId = p.id AND
                la1.label LIKE '%StandardParts%'
        )
    AND NOT EXISTS
        (
            SELECT 1
            FROM
                labelassign AS la2
            WHERE
                la2.partId = p.id AND
                la2.label LIKE '%SmallParts%'
        );

上面仍然返回list 记录,其中listitem 记录具有正确的标签SmallParts。同样,目标是过滤掉那些,因为我不需要修复它们。我正在寻找所有没有标签为 SmallPartslistitem 记录的 list 记录。

预期结果

id  name
--  ----
1   part1

只有 list.id 1 应该返回,因为它有一个 StandardParts 的标签,并且它的所有列表项都没有一个小部件的标签。 list.id 2 确实有一个 StandardParts 的标签,但它的一个列表项有一个 SmallParts 的标签,所以它应该被排除在外。

This question 涉及我的问题,但主要是面向 Java 的,答案并没有回答我的问题。

This question 再次刷过我的问题,但实际上是一个不同的问题,即另一个表中不存在的值,而不是基于值存在的排除。

如果我遗漏了什么,我很乐意提供更多信息。

【问题讨论】:

  • 当我第一次看到这个时,我认为从listpart 的关系是多对可能的,listItem 作为一个桥表。不过,现在我看到list 表中有partIds,我根本不了解表关系。我认为这确实需要确定的匹配和不匹配样本数据,以及预期的结果才能清楚。
  • 好的,我已经编辑了这个问题,希望能澄清预期的结果以及我认为应该如何获得它。这些表比我在这里显示的要复杂得多,但是我包含了相关部分,因此我删除了 list.partId 字段并重新编写了我的初始查询以使用 list.name 而不是 list.partId 来获取匹配部分的标签. list.name 应该匹配 part.name ,它应该有一个 part.id 匹配 labelassign.partId 我从中获取该列表的标签。
  • 您的样本数据似乎与 labelassign 中只有一个包含相关数据的列表非常不相关,并且您没有包含任何预期结果
  • 您说所有带有标签StandardParts 的列表都应该带有标签SmallParts 并且所有没有SmallParts 的列表都应该包括在内,但是没有StandardParts 和@987654354 的列表呢? @?是否也应包括在内?
  • 我明白了,我有相互矛盾的样本数据。我将对其进行编辑。

标签: mysql sql


【解决方案1】:

您希望对具有“SmallParts”的项目使用“LEFT JOIN”,并使用 WHERE 子句过滤掉匹配的行。您可以使用 « SELECT DISTINCT » 来避免重复。最后,我怀疑您不需要在表«部分»上加入,我将其删除。

SELECT DISTINCT 
    list.id, 
    list.name
FROM 
    list
    INNER JOIN listitem ON list.id = listitem.listId
    INNER JOIN labelassign l1 ON listitem.partId = l1.partId AND l1.labelId =  AND l1.label LIKE '%StandardParts%'
    LEFT JOIN labelassign l2 ON l2.partId = listitem.partId AND l2.label LIKE '%SmallParts%';
WHERE l2.partId IS NULL

【讨论】:

  • 这不会过滤掉没有像“%StandardParts%”这样的部件标签的列表记录,并且还会返回列表记录与带有“SmallParts”标签的部件相关联的列表记录。我认为我的内部联接使用过滤不正确。
  • @DustyVargas 这应该已经可以工作了...我简化了查询(在«部分»上不必要的加入)。但是,我在您的测试数据中看到了一个故障,其中表 listitem 中的大多数 «partId »s 不存在于表 «part » 和 «labelassign »
  • 没错,我没有发布完整的数据(从某种意义上说,我不会包括整个表格,它非常大)但为了清楚起见,我添加了引用的部分。我仍然得到额外的记录。我觉得第二个 INNER JOIN 应该让我无法获得标签不像 '%StandardParts%' 但事实并非如此的列表记录。我还有很多。
  • 也许我误解了最后一条语句的原因,但 labelassign.partId 永远不会为空
【解决方案2】:

我会尝试使用EXISTS 子句查找具有StandardParts 标签的list.ids,然后使用NOT EXISTS 子句将这些结果限制在没有部分具有SmallParts 标签的列表中。

SELECT 
  l.id, 
  l.name
FROM 
  list AS l
INNER JOIN 
  listitem AS li
    ON l.id = li.listId
INNER JOIN 
  part AS p
    ON li.partId = p.id
WHERE 
  EXISTS
    (
      SELECT 1
      FROM 
        labelAssign AS la1 
      WHERE 
        la1.partId = p.id AND
        la1.label LIKE '%StandardParts%'
    )
  AND NOT EXISTS
    (
      SELECT 1
      FROM 
        labelAssign AS la1 
      WHERE 
        la1.partId = p.id AND 
        la1.label LIKE '%SmallParts%'
    );

【讨论】:

  • 我相信你在 la1.labelId = 20 之后缺少一个 AND (​​我不会编辑,因为我是 mysql 新手并且不确定我是否正确)。不过,与其他答案相同,我得到标签不是“StandardParts”的列表和标签为“Small Parts”的列表的结果。
  • 另外,你能解释一下 SELECT 1 在这种情况下做了什么吗?
  • 在一个相关的子查询中(这就是你在[NOT] EXISTS 子句中所说的东西,你只是检查是否有任何记录符合条件。因为你没有返回任何结果,你只需要SELECT something1 是轻量级的。至于没有得到预期的结果,如果时间允许,我会用你更新的示例数据再过一遍已发布。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-16
  • 1970-01-01
  • 2018-02-07
  • 2020-05-08
相关资源
最近更新 更多