【问题标题】:SQL Select from many-to-oneSQL 多对一选择
【发布时间】:2023-04-10 00:20:02
【问题描述】:

我有两个包含一对多关系的表。我应该如何为“多”方选择“单”方给定信息?我正在使用SQLite

假设我们的第一个表 T1 是关于汽车的,第二个表 T2 是关于每辆车的缺陷的。

假设我们可以用一个整数来描述缺陷。

所以我们有:

CREATE TABLE T1 (
       id INTEGER PRIMARY KEY,
       [Other columns]
);

CREATE TABLE T2 (
       carId INTEGER REFERENCES T1(id),
       imperfection INTEGER
);

我们有几辆车的数据,每辆车都有许多缺陷。

给定一个代表缺陷的整数列表,我如何选择恰好具有这组缺陷的汽车?例如,假设我有 [1,5,7] 作为缺陷列表,我如何找出与汽车 19 匹配的?

如果有帮助,我希望每组独特的缺陷只有一个匹配项。

这个问题与DBA Stack Exchange question 中的问题类似,但是在上一个问题中,缺陷的数量是已知的。在这个问题中,我不知道不完美的数量。

【问题讨论】:

  • 做一个 GROUP BY,使用 HAVING 和 COUNT。
  • 什么意思不知道瑕疵的数量?您确实有一个类似 [1,5,7] 的列表。
  • @forpas 在链接的问题中,总是有两个不完美之处。结果,答案硬编码了这个假设。在这种情况下,预先不知道缺陷的数量。例如,下一个查询的列表可能是 [1,5,7,8]。
  • 好吧,看看我的答案。

标签: sql sqlite count having-clause


【解决方案1】:

您可以使用条件聚合。假设你没有重复:

select carid
from t2
group by carid
having sum(case when imperfection in (1, 5, 7) then 1 else 0 end) = 3;

这只会找到恰好具有 1、5 和 7 的汽车。如果您想要任何具有这些的汽车(可能还有其他汽车),您可以将其简化为:

select carid
from t2
where imperfection in (1, 5, 7)
group by carid
having count(*) = 3;

【讨论】:

  • 您的第一个解决方案也可能被选为接受的答案。不幸的是,我知道我只能接受一个答案。感谢您非常迅速的帮助。
  • @MatthewWalker。 . .除了成为第一名之外,它的作用与 GMB 的答案有些不同。我将这个问题解释为只需要 1、5 和 7 作为不完美,而不需要其他。这是第一个答案和在此基础上扩展的后续查询的基础。
  • 感觉sum(case when imperfection in (1, 5, 7) then 1 else 0 end) = 3相当于sum(imperfection in (1, 5, 7)) = 3 and sum(imperfection not in (1, 5, 7)) = 0。 (尽管您的答案很可能在计算上更有效)。你同意吗?如果这两个子句是等价的,那么我觉得这两个答案是等价的。还是我错过了什么?
  • 鉴于只需要通过一次缺陷列表(而不是 GMB 的方法两次)的优势,我改变了主意并采用了这个解决方案。
【解决方案2】:

你可以使用聚合:

select carId
from t2
where imperfection in (1, 5, 7)
group by carId
having count(*) = 3

这带来了具有所有 3 个缺陷的汽车。如果您还想排除有其他缺陷的汽车,那么:

select carId
from t2
group by carId
having
    sum(imperfection in (1, 5, 7)) = 3
    and sum(imperfection not in (1, 5, 7)) = 0

【讨论】:

  • 我采用了您的第二种方法。尽管我的问题并不清楚,但我一直在寻找完全匹配的匹配项,您的回答以一种非常容易理解的方式提供了该匹配项。谢谢。
  • 对于那些有兴趣在 Python 下使用 SQLite 应用上述解决方案的人,我发现传入不完美整数列表是一个挑战,但是这个 stackoverflow 答案很有帮助:stackoverflow.com/a/5766293/562930
  • 因为这个答案要求我通过两次缺陷列表,所以我改变了主意,选择了@GordonLinoff 的答案。我仍然觉得这个答案更容易理解。
【解决方案3】:

如果您将缺陷列表作为一个排序的逗号分隔字符串,例如'1,5,7',那么您可以使用group_concat() 窗口函数:

select carId
from (
  select *,
    row_number() over (partition by carId order by imperfection desc) rn,
    group_concat(imperfection) over (partition by carId order by imperfection) imperfections
  from T2
)   
where rn = 1 and imperfections = '1,5,7'

查看简化的demo

【讨论】:

  • 感谢有趣的替代方法,尤其是演示。
猜你喜欢
  • 1970-01-01
  • 2011-03-30
  • 1970-01-01
  • 2010-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-22
相关资源
最近更新 更多