SQL改进-联合?

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

我有两张桌子:包裹和物品

包裹有以下列:包裹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
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