从一个表中选择多个值,在一行中的另一表中具有匹配的记录

Abd*_*ani 1 postgresql join pivot

我有两个表如下:

create table first (id int, name varchar(20));
create table second (id int, value char(1),fid int);  
Run Code Online (Sandbox Code Playgroud)

这些表具有以下记录:

insert into first values (1,'Ahmad'),(2,'Sami'),(3,'Khan');
insert into second values
  (1,'a',1)
, (2,'b',1)
, (3,'c',2)
, (4,'d',1)
, (5,'e',2)
, (6,'f',3);  
Run Code Online (Sandbox Code Playgroud)

我想从表中选择那些在表second中具有匹配记录first单行记录

所需的输出是:

身份证 | 姓名 | 价值 | 价值 | 价值
 ---+-------+-------+-------+-------
  1 | 艾哈迈德 | | 乙 | d
  2 | 萨米语 | | | 电子 |
  3 | 汗 | f | |  

table 的单个记录的值数量first不受限制, table 的单个记录可以有n多个值first

n未知,但我需要为valuetablesecond中具有匹配记录的 table 中的每个值重复该列first。我需要像上面一样的整张桌子The desired result。我只需要 table 引用的那些行second。Postgres 的版本将是最新的。

Erw*_*ter 6

其实,自从

ntable 的单个记录可以有多个值first

要返回的列数并不是任意的。有最多列,这有一个干净的解决方案 - 除非你的列比Postgres 允许的表多:

250 - 1600 取决于列类型

顺便说一句,通常情况下,您还会有一个third表,列出 的所有可能值value,整个表实现了经典的多对多关系。

您可以使用CASE语句,或者更优雅地使用crosstab()附加模块的功能tablefunc。如果您不熟悉它,请先阅读此处的基本说明:

实际值右侧的列填充为 NULL。假设最多 5 个可能的值并以此设置为基础:

CREATE TABLE first  (id int, name text);
CREATE TABLE second (id int, value "char", fid int);  

INSERT INTO first  VALUES
  (1,'Ahmad')
, (2,'Sami')
, (3,'Khan')
, (4,'Nobody');  -- Added to demonstrate difference
INSERT INTO second VALUES
  (1,'a',1)
, (2,'b',1)
, (3,'c',2)
, (4,'d',1)
, (5,'e',2)
, (6,'f',3);
Run Code Online (Sandbox Code Playgroud)

要么使用crosstab(text)(1个参数形式)并first再次加入表格:

SELECT id, f.name, value1, value2, value3, value4, value5
FROM   crosstab(
        'SELECT f.id, 1 AS dummy_category, s.value
         FROM   first  f
         JOIN   second s ON s.fid = f.id
         ORDER  BY f.id, s.value'
       ) ct (id int
           , value1 "char", value2 "char", value3 "char", value4 "char", value5 "char")
JOIN first f USING (id);
Run Code Online (Sandbox Code Playgroud)

或者使用crosstab(text, text)(2 个参数形式)并为您的值生成虚拟类别:

SELECT *
FROM   crosstab(
        'SELECT f.id, f.name
              , row_number() OVER (PARTITION BY f.id ORDER BY s.value) AS dummy_category
              , s.value
         FROM   first  f
         JOIN   second s ON s.fid = f.id
         ORDER  BY f.id, s.value'
      , ('SELECT generate_series(1,5)')
       ) ct (id int, name text
           , value1 "char", value2 "char", value3 "char", value4 "char", value5 "char");
Run Code Online (Sandbox Code Playgroud)

结果是一样的:

 id | name  | value1 | value2 | value3 | value4 | value5
----+-------+--------+--------+--------+--------+--------
  1 | Ahmad | a      | b      | d      |        |
  2 | Sami  | c      | e      |        |        |
  3 | Khan  | f      |        |        |        |
Run Code Online (Sandbox Code Playgroud)

如果您要包括所有从表行第一,使之成为LEFT [OUTER] JOIN

         ...
         LEFT JOIN second s ON s.fid = f.id
         ...
Run Code Online (Sandbox Code Playgroud)

然后我们为上面的例子得到一个额外的结果行:

  4 | Nobody |        |        |        |        |
Run Code Online (Sandbox Code Playgroud)