【问题标题】:Get distinct individual column values (not distinct pairs) from two tables in single query在单个查询中从两个表中获取不同的单个列值(不是不同的对)
【发布时间】:2015-05-31 02:02:47
【问题描述】:

我有两个如下表。一是针对某些人的体育人才,二是针对艺术人才。一个人可能没有要列出的体育人才,同样适用于艺术人才。

CREATE TABLE SPORT_TALENT(name varchar(10), TALENT varchar(10));
CREATE TABLE ART_TALENT(name varchar(10), TALENT varchar(10));

INSERT INTO SPORT_TALENT(name, TALENT) VALUES
  ('Steve', 'Footbal')
 ,('Steve', 'Golf')
 ,('Bob'  , 'Golf')
 ,('Mary' , 'Tennnis');

INSERT INTO ART_TALENT(name, TALENT) VALUES
  ('Steve', 'Dancer')
, ('Steve', 'Singer')
, ('Bob'  , 'Dancer')
, ('Bob'  , 'Singer')
, ('John' , 'Dancer');

现在我想列出一个人的运动天赋和艺术天赋。我想避免重复。但我不介意任何输出中是否有“null”。我尝试了以下

select distinct sport_talent.talent as s_talent,art_talent.talent as a_talent
from sport_talent
JOIN art_talent on sport_talent.name=art_talent.name
where (sport_talent.name='Steve' or art_talent.name='Steve');

 s_talent | a_talent 
----------+----------
 Footbal  | Dancer
 Golf     | Singer
 Footbal  | Singer
 Golf     | Dancer

我想避免冗余,需要类似以下的东西(体育人才的独特价值观+艺术人才的独特价值观)。

 s_talent | a_talent 
----------+----------
 Footbal  | Dancer
 Golf     | Singer

如主题中所述,我不是在寻找不同的组合。但同时,如果某一列中有一些值为“null”的记录,也可以。我对 SQL 比较陌生。

【问题讨论】:

  • 因此,在您的结果中,s_talent 值和 a_talent 值之间没有关系。您只是有两个并排显示的独立列表?
  • @Vimt 如果您查看数据 steve 踢过足球和高尔夫,如果您将这个结果与 steve 的艺术天赋结合起来,它有舞蹈家和歌手,因此唱歌踢过足球和高尔夫,而歌手踢过高尔夫和足球。这就是解释 4 行结果的原因
  • 您运行的是当前版本的 Postgres 9.4 吗? (总是添加你的版本!)
  • @Turophile:是的,两个独立的列表并排显示。 s_talent 和 a_talent 之间没有关系。无论如何,我从 Erwin 和 kordirko 那里得到了答案

标签: sql postgresql outer-join distinct-values


【解决方案1】:

Postgres 9.4

...介绍unnest() with multiple arguments。完全符合您的要求,并且也应该很快。 Per documentation:

特殊表函数UNNEST 可以用任意数量的 数组参数,它返回相应的列数,如 如果 UNNEST(第 9.18 节)已分别在每个参数上调用 并使用ROWS FROM 构造进行组合。

关于ROWS FROM

SELECT *
FROM   unnest(
         ARRAY(SELECT DISTINCT talent FROM sport_talent WHERE name = 'Steve')
       , ARRAY(SELECT DISTINCT talent FROM art_talent WHERE name = 'Steve')
       ) AS t(s_talent, a_talent);

Postgres 9.3 或更早版本

SELECT s_talent, a_talent
FROM  (
   SELECT talent AS s_talent, row_number() OVER () AS rn
   FROM   sport_talent
   WHERE  name = 'Steve'
   GROUP  BY 1
   ) s
FULL JOIN (
   SELECT talent AS a_talent, row_number() OVER () AS rn
   FROM   art_talent
   WHERE  name = 'Steve'
   GROUP  BY 1
   ) a USING (rn);

更多解释的类似先前答案:

这类似于@kordirko posted,但使用GROUP BY 来获得不同的天赋,这是在窗口函数之前 评估的。所以我们只需要一个简单的row_number() 而不是更昂贵的dense_rank()

关于SELECT 查询中的事件序列:

SQL Fiddle.

【讨论】:

  • 谢谢@Erwin。正是我想要的。我正在使用 Postgres 9.2。测试了所有的组合。我会花一些时间来理解它......
【解决方案2】:

您的查询中没有重复项。查询返回中的四条记录中的每一条都是唯一的。这个结果可能不是你想要的,但似乎它的问题不在于重复。

【讨论】:

    【解决方案3】:

    试试:

    SELECT s_talent, a_talent
    FROM (
      SELECT distinct on (talent) talent as s_talent,
            dense_rank() over (order by  talent) as x
      FROM SPORT_TALENT
      WHERE name='Steve'
    ) x
    FULL OUTER JOIN (
      SELECT distinct on (talent) talent as a_talent,
            dense_rank() over (order by  talent) as x
      FROM ART_TALENT
      WHERE name='Steve'
    ) y
    ON x.x = y.x
    

    演示:http://sqlfiddle.com/#!15/66e04/3

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-21
      • 2021-06-06
      • 1970-01-01
      相关资源
      最近更新 更多