SQL改进 - UNION?

时间:2017-11-14 14:28:48

标签: sql sql-server tsql

我有两张桌子:"包"和"项目"。

" packages"有以下列:pack_id | item_id

" items"有以下列.......:item_id | type

一个可以包含多个 商品

更新:

样本数据和预期结果:

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

我的问题是:

有没有更好的方法来查询这两个表,以获得第三个表,具有列:" pack_id"和新专栏" pack_type"?这些UNION似乎为运行时间增加了大量时间。

    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

注意:多个注释的一些解释指向&#34; A类型不能是Z,也不能是C或F&#34;。

我也这么认为,但我理解查询行为的方式是,如果你说&#34;输入IN(&#39; C&#39;,&#39; F&#39;)&# 34;它将查看每个类型的项目&#39; C&#39;或者&#39; F&#39;并获取具有该项目的包ID。但是,包装类型为&#39; C&#39;或者&#39; F&#39;也可以有类型&#39; Z&#39;的项目,因此内部选择,处理类型&#39; Z&#39;第一

3 个答案:

答案 0 :(得分:5)

也许我误解了一些东西,但这不是你真正想要的东西:

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

有三种类型:酷或不酷,以及其他一切,你不需要过滤器(只是唯一的)。

答案 1 :(得分:1)

即使没有解释这个问题,我猜你的包类型是从它上面的项目组合中得出的。所以你需要对每个包装上的物品进行分组

<强> SQL DEMO

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

<强>输出

enter image description here

答案 2 :(得分:0)

我认为你可以把它放在像这样的单一查询中

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的回答是正确的