2010-06-08 3 views
2

У меня есть две таблицы:Выберите запрос союза?

Таблица 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?

+0

Я думаю, что ваш 'столбец Id' в результатах следует читать '4 Анди ... 5 Джесс. – eykanal

ответ

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 
) 

На самом деле, вам нужно только ВЛЕВО и 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  
+0

Я выбрал ваш второй запрос, поскольку он был намного быстрее, чем отдых. Спасибо!!! – Kris1511

-1

Неверный ответ Вы ищете «союзный отдельный», а не просто союз. Исправлено, когда я получил удар и понял, что неправильно прочитал вопрос.

Создайте битовую маску, как показано ниже, используя простую обозначение мощности, чтобы сделать ее более ясной, чтобы im просто вставлял степень усыновления 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 
+0

Это не сработает; он хочет знать, из каких таблиц каждый пришел, разные просто удаляют дубликаты. – eykanal

+1

-1: UNION является синонимом UNION DISTINCT. См. Руководство: http://dev.mysql.com/doc/refman/5.0/en/union.html –

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 

... хотя я не уверен, это действительно.

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 
+0

+1 Это хорошо работает –

+0

Кроме того, логика для столбца 'Id' в результате выглядит как' COALESCE (x.id, y.id) '. – VeeArr

+0

@VeeArr: Вы имеете в виду 'COALESCE (y.id, z.id) ':) –

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  | 
+-------+-------+ 
Смежные вопросы