【问题标题】:SQL Query with two tables and need to search one of the tables for specific and multiple column values具有两个表的 SQL 查询,需要在其中一个表中搜索特定和多列值
【发布时间】:2020-10-07 14:21:41
【问题描述】:

我需要编写一个涉及下面两个示例表的复杂查询,我正在努力理解如何正确构建查询。

表格结构如下,连同样本数据:

Table 1:
ID | Type | Size
A123 | Block | Medium
C368 | Square | Large
X634 | Triangle | Small
K623 | Square | Small
Table 2:
ID | Code | Description | Price
A123 | C06 | Sensitive Material | 99.99
A123 | H66 | Heavy Grade | 12.76
A123 | U74 | Pink Hue | 299.99

C368 | H66 | Heavy Grade | 12.76
C368 | G66 | Green Hue | 499.99
C368 | C06 | Sensitive Material | 99.99
C368 | K79 | Clear Glass | 59.99

X634 | G66 | Green Hue | 499.99
X634 | K79 | Clear Glass | 59.99
X634 | Z63 | Enterprise Class | 999.99

K623 | K79 | Clear Glass | 59.99
K623 | G66 | Green Hue | 499.99
K623 | X57 | Extra Piping | 199.99

查询应主要基于表 1 中的 Type 列,然后加入表 2 的 ID 列。查询的目标是搜索表 1 中具有特定 @987654325 的所有 ID表 2 中的 @ 列组合。

对于 Type = Square AND both (Code = G66 AND Code = K79),最终输出应该是这样的表格:

ID 
C368
K623

应该返回这两个 ID,因为它们在上面的伪查询中都有 BOTH 选项代码。

如何使用这两个表组合这个结果?以下是我编写的两个初始查询 - 都不会产生正确的结果。如您所见,我已尝试使用 IN 运算符和 =/AND/OR 运算符。

尝试 1(似乎可以使用 ONE 代码,但不能使用 > 1 代码):

select distinct ID
from
(
SELECT shapes.ID, details.code, details.description
FROM db.table2 details 
JOIN db.table1 shapes
ON details.VIN = shapes.VIN
WHERE shape.type='Square'
) src
where code IN ("G66", "K79")
-- where code = "G66" AND code = "K79" (Produces zero results)
-- where code = "G66" OR code = "K79" (Produces incorrect results)

尝试 2(似乎适用于 ONE 代码,但不适用于 > 1 个代码):

SELECT distinct ID
FROM db.table2 details
WHERE ID IN
(
    SELECT ID FROM db.table1 shapes 
    WHERE shapes.type='Square' 
) AND code IN ("G66", "K79")
-- AND code = "G66" AND code = "K79" (produces zero results)
-- AND code = "G66" OR code = "K79" (Produces incorrect results)

谢谢

【问题讨论】:

  • Table1 包含 Type 列,用于在从 Table2 收集其他详细信息之前按类型过滤 ID。

标签: mysql sql join


【解决方案1】:

每当您遇到类似问题“我需要此表中的 ID,其中一行的值为 A,另一行的值为 B,并且两行都具有相同的 ID”时,您需要选择所有匹配您的条件的行,对它们进行分组,然后对它们进行计数,并且只使用具有匹配计数的行:

SELECT t2.id
FROM table1 t1 JOIN table2 t2 ON t1.id = t2.id
WHERE t1.type = 'square' and t2.code IN ('G66', 'K79')
GROUP BY t2.id
HAVING COUNT(*) = 2

如果可能有一些虚假的结果,比如两行是 G66,而没有行是 K79,那么这个简单的计数就会失败。我们可以使用 MIN 和 MAX 来查看值(如果是 2):

SELECT t2.id
FROM table1 t1 JOIN table2 t2 ON t1.id = t2.id
WHERE t1.type = 'square' and t2.code IN ('G66', 'K79')
GROUP BY t2.id
HAVING MIN(t2.code) = 'G66' AND MAX(t2.code) = 'K79'

之所以有效,是因为按字母顺序 G66 小于 K79,所以 G66 将是最小的

如果我们必须强制要求 3 个值,我们可以做一些技巧,比如将所有代码变成一个数字,并要求总和是某个值。我将为此使用基数 2:

SELECT t2.id
FROM table1 t1 JOIN table2 t2 ON t1.id = t2.id
WHERE t1.type = 'square' and t2.code IN ('G66', 'K79', 'X99')
GROUP BY t2.id
HAVING SUM(CASE t2.Code WHEN 'G66' THEN 1 WHEN 'K79' THEN 2 WHEN 'X99' THEN 4 END) = 7

如果我们将它们映射到 1、2 和 4,那么生成 7(如果值是唯一的)的唯一方法是每个都有一个。如果可能有 7 个 G66 而其他一个都没有,给出一个虚假的结果,那么我们可能不得不单独计算它们:

SELECT t2.id
FROM table1 t1 JOIN table2 t2 ON t1.id = t2.id
WHERE t1.type = 'square' and t2.code IN ('G66', 'K79', 'X99')
GROUP BY t2.id
HAVING 
  SUM(CASE t2.code WHEN 'G66' THEN 1 ELSE 0 END) = 1 AND
  SUM(CASE t2.code WHEN 'K79' THEN 1 ELSE 0 END) = 1 AND
  SUM(CASE t2.code WHEN 'X99' THEN 1 ELSE 0 END) = 1 

【讨论】:

  • 我认为您的第一个查询已经完成,因为不可能有重复的代码行。我假设如果我想对 3 或 4 个选项代码进行搜索,那么 HAVING 子句将需要相应地更新它的编号 - 正确吗?
  • 完全正确 - IN 列表中的事物数量应与您要求的数量相同。这里的核心概念是您正在寻找跨不同行的数据。 WHERE 子句只对同一行的不同列进行操作,而 GROUPing 跨行操作
  • 既然如此,我相信您的第一个查询可以完美运行。谢谢!
【解决方案2】:

这是我的想法。

通过 where 子句过滤 t1 中的数据,然后加入 t2 2 次,每次按条件过滤以使 G66 和 K79 在同一个表中(2 个不同的连接)

Select t1.ID 
from t1 
inner join t2 as t2_G66 on t1.ID = t2_G66.ID
inner join t2 as t2_K79 on t1.ID = t2_K79.ID
where t1.Type = 'Square' and 
    t2_G66.Code = 'G66' and 
    t2_K79.Code = 'K79' 

这里是fiddle

【讨论】:

  • 感谢您的努力,但我无法让此查询产生任何结果。其实我在执行的时候遇到了MySql查询超时300秒。
【解决方案3】:

由于表 1 和表 2 是按 ID 关联的,所以在获取具有我们正在寻找的类型的相关行之后,您难道不能在表 1 中的 id 上使用 INNER JOIN 吗?

我想我们可以先进行查询以获取所有具有相关类型的行,然后运行 ​​INNER JOIN 以获取具有我们关心的 ID 的共享行。

最后,我们可以按代码列对结果进行分组吗?

也许这样的东西可以工作?:

SELECT * FROM db.table1 WHERE db.table1.type = "whatever"
INNER JOIN db.table2 ON db.table1.id = db.table2.id
GROUP BY db.table2.code HAVING COUNT(*) >= 1
AND db.table2.code IN ("code_1, code_2, code_3")

我刚开始使用 SQL,所以希望如此!

附:我意识到我没有涵盖您让代码成为您关心的代码子集的成员的条件。所以我认为这可能有效。

【讨论】:

  • @Caius Jard 你能评论一下这个查询吗?完全不相关的大声笑
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-18
  • 1970-01-01
  • 1970-01-01
  • 2021-04-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多