SQL改进-联合?
我有两张桌子:包裹和物品 包裹有以下列:包裹id |物品id 项目有以下列……:项目| id |类型 一个包可以有多个项目 更新: 样本数据和预期结果:SQL改进-联合?,sql,sql-server,tsql,Sql,Sql Server,Tsql,我有两张桌子:包裹和物品 包裹有以下列:包裹id |物品id 项目有以下列……:项目| id |类型 一个包可以有多个项目 更新: 样本数据和预期结果: pack_id | item_id 1 1 1 2 1 3 2 2 2 1 3 4 3 5 3 6 item_id | type 1 C 2 F
pack_id | item_id
1 1
1 2
1 3
2 2
2 1
3 4
3 5
3 6
item_id | type
1 C
2 F
3 Z
4 Z
5 Z
6 Z
预期结果:
pack_id | pack_type
1 Mixed
2 Cool
3 Not Cool
我的问题是:
有没有更好的方法来查询这两个表,以获得第三个表,其中包含as列:pack\u id和新的列pack\u type?这些工会似乎给运行时间增加了大量时间
SELECT pack_id, pack_type
FROM (
-- CASE 1 - pack_type is 'Cool' - type 'C' or 'F', but not 'Z'
SELECT Distinct q1.pack_id, 'Cool' AS pack_type
FROM (
SELECT Distinct p.pack_id, i.type
FROM packages p
INNER JOIN items i
ON p.item_id = i.item_id
WHERE i.type <> 'Z') q1
WHERE q1.type IN ('C','F')
UNION
-- CASE 2 - pack_type is 'Not-Cool' - type 'Z', but not 'C' or 'F'
SELECT Distinct q2.pack_id, 'Not-Cool' AS pack_type
FROM (
SELECT Distinct p.pack_id, i.type
FROM packages p
INNER JOIN items i
ON p.item_id = i.item_id
WHERE i.type = 'Z') q2
WHERE q2.type NOT IN ('C','F')
UNION
-- CASE 3 - pack_type is 'Mixed' - type 'Z' and ('C' or 'F')
SELECT Distinct q3.pack_id, 'Mixed' AS pack_type
FROM (
SELECT Distinct p.pack_id, i.type
FROM packages p
INNER JOIN items i
ON p.item_id = i.item_id
WHERE i.type = 'Z') q3
WHERE q3.type IN ('C','F')
) m
注意:对于指向一个类型的多个注释的一些解释不能是Z,也不能是C或F
我也这么想,但我理解查询行为的方式是,如果你说键入'C','F',它将查看'C'或'F'类型的每个项,并获得包含该项的包id。但是,包含类型为“C”或“F”的项的包也可以包含类型为“Z”的项,因此内部选择首先处理类型为“Z”的项。我认为您可以将其放入这样的单个查询中
SELECT Distinct *
FROM (
SELECT p.pack_id,
CASE WHEN i.type <> 'Z' AND i.type IN ('C','F') THEN 'Cool'
WHEN i.type = 'Z' AND i.type NOT IN ('C','F') THEN 'Not-Cool'
WHEN i.type = 'Z' AND i.type IN ('C','F') THEN 'Mixed'
END AS pack_type
FROM packages p
INNER JOIN items i ON p.item_id = i.item_id
WHERE (i.type <> 'Z' AND i.type IN ('C','F'))
OR (i.type = 'Z' AND i.type NOT IN ('C','F'))
OR (i.type = 'Z' AND i.type IN ('C','F'))
) as temp
更新:仔细检查您的逻辑后,我认为@Tim answer是正确的也许我误解了什么,但这不是您真正想要的:
SELECT DISTINCT
pack_id,
pack_type = CASE WHEN i.type IN ('C','F') THEN 'Cool'
WHEN i.type IN ('Z') THEN 'Not-Cool'
ELSE 'Mixed' END
FROM packages p INNER JOIN items i ON p.item_id = i.item_id
有三种类型:酷或不酷,以及其他所有类型,您不需要一个唯一的过滤器。即使我没有解释这个问题,我猜您的包装类型是由其上的项目组合衍生而来的。因此,您需要对每个包上的项目进行分组 输出
UNION比UNION ALL慢一点,因为它必须检查重复项。但您应该能够在一个查询中使用一些大小写表达式来完成整个任务。@Sean。。我只是输入它来根据类型建议案例。您还可以存储一个过程,将选择的结果放入临时表中。最后返回夯实表;也许我在原始查询中遗漏了一些东西,但是第二个和第三个查询中的q1.type如何引用第一个查询?@WEI_DBA应该是q2和Q3我想你可以将Where条件简化为I.type in'C'、'F'或I.type='Z'@JuanCarlosOropeza不会I.type in'C'、'F',“Z”和你的一样吗?@JuanCarlosOropeza我想蒂姆明白了你犯了和OP一样的逻辑错误:当I.type='Z'和I.type输入'C','F'时,我认为你是对的。输入'C'或'F',而不是'Z'只是输入'C'或'F'@JuanCarlosOropeza:是的,而且这也不会产生一个敏感的子查询:type='Z'。。。然后输入'C','F'。类型不能是Z,也不能是C或带有@TimSchmelter的FAgree。我只是说…:-我想我们理解错了这个要求。包裹是物品的组合。所以某个地方需要一个小组。这就是为什么可以有混合包。@JuanCarlosOropeza:可能,但是缺少信息。在查询的注释中解释了如何确定包类型。请看我添加到问题中的注释。它解释了为什么建议的解决方案没有给出正确的结果。我的查询产生了您确切的愿望输出。请检查演示,这是真的。我必须理解它的逻辑,但它也非常快,50分钟对4分钟。非常感谢。我看你没有使用DISTINCT。我看不到任何重复项,但只是为了确保这里不需要它?不,您正在解决的问题是,使用GROUP BY和COUNT btw 4 min仍然很重要,您需要为package item.id创建一个索引,并为item item_id创建一个复合索引,键入。实际上,我发现了一些重复项,因此我在第二次选择中使用了DISTINCT。如果那是错的,请告诉我
WITH cte as (
SELECT pack_id,
COUNT(CASE WHEN i.type IN ('C','F') THEN 1 END) as total_CF,
COUNT(CASE WHEN i.type = 'Z' THEN 1 END) as total_Z
FROM packages p
INNER JOIN items i
ON p.item_id = i.item_id
GROUP BY pack_id
)
SELECT pack_id,
CASE WHEN total_CF > 0 and total_Z = 0 THEN 'Cool'
WHEN total_CF = 0 and total_Z > 0 THEN 'Not Cool'
WHEN total_CF > 0 and total_Z > 0 THEN 'Mixed'
-- ELSE 'NOT determinated'
END as type
FROM cte