sql - 匹配不同列位置中的两个相同值

sql - match two of the same values in different column positions

我希望在 id 上加入两个不同的 table,并且需要从每个 table 中提取唯一名称;如果一个 table 有特定名称而另一个没有,则应该有一个值和一个空值。反之亦然。

使用联接,当前输出如下所示:

id  name_1  name_2
1   max     steph
1   max     john
1   john    chris
1   john    chris
1   chris   steph
1   chris   null
1   null    max
1   null    null
1   tony    john
1   tony    max

预期输出:

id  name_1  name_2
1   max     max
1   john    john
1   chris   chris
1   null    steph
1   tony    null

当前 sql:

select
table1.id,
table1.name as name_1,
table2.name as name_2
from table1
left join table2
on table1.id = table2.id

(雪花)

以下内容可用于此 -

with cte as
(
select distinct t1.id,name_1 from t1)
select distinct ifnull(t2.id,cte.id) id,
cte.name_1,
t2.name_2
from t2 full outer join cte
ON cte.id=t2.id
and cte.name_1 = t2.name_2
order by cte.name_1;
+----+--------+--------+
| ID | NAME_1 | NAME_2 |
|----+--------+--------|
|  1 | chris  | chris  |
|  1 | john   | john   |
|  1 | max    | max    |
|  1 | tony   | NULL   |
|  1 | NULL   | steph  |
+----+--------+--------+

添加 WHERE 子句。

select
table1.id,
table1.name as name_1,
table2.name as name_2
from table1
left join table2
WHERE table1.name = table2.name 
OR table1.name is null
OR table2.name is null 
on table1.id = table2.id

如果您只需要一个唯一名称列表

select distinct name from table1
union
select distinct name from table2
SELECT
   NVL(d1.id, d2.id) as id,
   d1.name as name_1,
   d2.name as name_2
FROM (
     SELECT DISTINCT id,name FROM table1
) AS d1
FULL OUTER JOIN (
     SELECT DISTINCT id,name FROM table2
) AS d2
    ON d1.id = d2.id AND d1.name = d2.name
ORDER BY 1, (d1.name,d2.name)

这从两个 table 中获取不同的 id、name 对,然后完全外部连接这些值集。因此,如果 id,name 在两者中都匹配。如果它们不匹配,它们仍然会保留。

所以这些 CTE 提供了假数据:

WITH table1(id,name) AS (
    select * from values (1,'aa'),(1,'ab'),(2,'ba')
), table2(id,name) AS (
    select * from values (1,'aa'),(1,'ac'),(2,'ba'),(2,'bb')
)
ID NAME_1 NAME_2
1 aa aa
1 ab null
1 null ac
2 ba ba
2 null bb

西蒙斯的回答是必经之路,因为 snowflake 支持 full outer joins。但是对于那些使用不支持完全外部连接的关系数据库并且有同样问题的人来说,这种方法可以作为替代方法:

select id, 
       if(instr(group_concat(tb), 1), name, NULL) name_1, 
       if(instr(group_concat(tb), 2), name, NULL) name_2 
from(
    select id, name, 1 tb from table1
    union
    select id, name, 2 tb from table2
) a
group by id, name
order by name

结果:

| id  | name_1 | name_2 |
| --- | ------ | ------ |
| 1   | chris  | chris  |
| 1   | john   | john   |
| 1   | max    | max    |
| 1   | null   | steph  |
| 1   | tony   | null   |

假数据:

CREATE TABLE table1 (
  id int(11),
  name varchar(50)
  );
  
CREATE TABLE table2 (
  id int(11),
  name varchar(50)
  );  
  
INSERT INTO table1 VALUES
    (1, 'max'),
    (1, 'john'),
    (1, 'chris'),
    (1, 'tony');

INSERT INTO table2 VALUES
    (1, 'steph'),
    (1, 'john'),
    (1, 'chris'),
    (1, 'max');

还有一个 dbfiddle:https://www.db-fiddle.com/f/gQ4U7hu2S2EyFEtZrapqdu/6