选择Union Query?

时间:2010-06-08 18:23:27

标签: mysql

我有两张桌子:

表A:

id  name
------------    
1   Scott
2   Dan
3   Sam

表B:

id  name
------------    
1   Dan
2   Andi
3   Jess

我的结果必须是:

Id Name  Found
1  Scott A
2  Dan   C i.e. found in both
3  Sam   A
2  Andi  B
3  Jess  B

我可以使用UNION获取结果,但如何创建Found列?

5 个答案:

答案 0 :(得分:4)

使用:

  SELECT CASE 
           WHEN y.name IS NULL THEN z.id
           WHEN z.name IS NULL THEN y.id
           ELSE y.id
         END AS id,
         x.name,
         CASE 
           WHEN y.name IS NULL THEN 'B'
           WHEN z.name IS NULL THEN 'A'
           ELSE 'C'
         END AS found
    FROM (SELECT a.name
            FROM TABLE_A a
          UNION 
          SELECT b.name
            FROM TABLE_B b) x
LEFT JOIN TABLE_A y ON y.name = x.name
LEFT JOIN TABLE_B z ON z.name = x.name

替代:

  SELECT COALESCE(y.id, z.id) AS id,
         x.name,
         CASE 
           WHEN y.name IS NULL THEN 'B'
           WHEN z.name IS NULL THEN 'A'
           ELSE 'C'
         END AS found
    FROM (SELECT a.name
            FROM TABLE_A a
          UNION 
          SELECT b.name
            FROM TABLE_B b) x
LEFT JOIN TABLE_A y ON y.name = x.name
LEFT JOIN TABLE_B z ON z.name = x.name

答案 1 :(得分:1)

执行此操作的方法是使用FULL OUTER JOIN,但由于MySQL不支持,因此您可以使用LEFT JOIN和INNER JOIN以及RIGHT JOIN的组合。

(
    SELECT A.Id, A.Name, 'A' AS Found
    FROM A LEFT JOIN B ON A.Name = B.Name
    WHERE B.Name IS NULL
)
UNION ALL
(
    SELECT B.Id, B.Name, 'B' AS Found
    FROM A RIGHT JOIN B ON A.Name = B.Name
    WHERE A.Name IS NULL
)
UNION ALL
(
    SELECT A.Id, A.Name, 'C' AS Found
    FROM A JOIN B ON A.Name = B.Name
)

实际上,您只需要LEFT和RIGHT JOIN,因为您可以在执行其他两个连接之一的同时处理INNER JOIN。我认为上面的原理更清楚地说明了原理,但在实践中,以下内容会提供更好的表现:

SELECT A.Id, A.Name, IF(B.Name IS NULL, 'A', 'C') AS Found
FROM A LEFT JOIN B ON A.Name = B.Name
UNION ALL
SELECT B.Id, B.Name, 'B' AS Found
FROM A RIGHT JOIN B ON A.Name = B.Name
WHERE A.Name IS NULL

结果:

Id  Name   Found
1   Scott  A    
2   Dan    C    
3   Sam    A    
2   Andi   B    
3   Jess   B    

答案 2 :(得分:0)

在我看来,你有效地希望同时进行左右连接。这在技术上是不可能的,因为您总是需要一个参考表。我能想到的唯一方法是:

SELECT tableA.*
  LEFT JOIN tableB.* USING name
UNION DISTINCT SELECT tableB.*
  LEFT JOIN tableA USING name

在考虑了一些之后,你也可以做到:

SELECT tableA.*
  LEFT JOIN  tableB.* USING name
  RIGHT JOIN tableB.* USING name

......虽然我不确定这是否有效。

答案 3 :(得分:0)

select tmp.name, case count(*) when 1 then tmp.tbl else 'C' end found 
  from (select id, name, 'A' tbl from TableA 
        union all 
        select id, name, 'B' tbl from TableB) as tmp 
 group by tmp.name;

+-------+-------+
| name  | found |
+-------+-------+
| Andi  | B     |
| Dan   | C     |
| Jess  | B     |
| Sam   | A     |
| Scott | A     |
+-------+-------+

答案 4 :(得分:-1)

错误的答案 你正在寻找“联盟不同”而不仅仅是联盟。 纠正我什么时候被击倒并意识到我错误地阅读了这个问题。

使用简单的电源表示法生成如下的位掩码,使其更清晰,我只需为位掩码插入2的强制转换功能。

with data as (
SELECT Id,Name, 2^0 as bitmask FROM A
UNION ALL 
SELECT Id,Name, 2^1 as bitmask FROM B
UNION ALL 
SELECT Id,Name, 2^2 as bitmask FROM C)
SELECT Id,Name, SUM(bitmask)
FROM data
GROUP BY Id,Name