5

可以说我有一个table1

  id      name
-------------
  1       "one"
  2       "two"
  3       "three"

第一个table2带有外键的a:

id    tbl1_fk    option   value
-------------------------------
 1      1         1        1
 2      2         1        1
 3      1         2        1
 4      3         2        1

现在我想有一个查询结果:

table1.id | table1.name | option | value
-------------------------------------
      1       "one"        1       1
      2       "two"        1       1
      3       "three"    
      1       "one"        2       1
      2       "two"    
      3       "three"      2       1

我该如何做到这一点?

我已经尝试过:

SELECT
  table1.id,
  table1.name,
  table2.option,
  table2.value
FROM table1 AS table1
LEFT outer JOIN table2 AS table2 ON table1.id = table2.tbl1fk

但结果似乎省略了空值:

1    "one"    1   1
2    "two"    1   1
1    "one"    2   1
3    "three"  2   1

已解决:感谢 Mahmoud Gamal:(加上 GROUP BY)已解决此查询

SELECT 
  t1.id,
  t1.name,
  t2.option,
  t2.value
FROM
(
  SELECT t1.id, t1.name, t2.option
  FROM table1 AS t1
  CROSS JOIN table2 AS t2
) AS t1
LEFT JOIN table2 AS t2  ON t1.id = t2.tbl1fk
                       AND t1.option = t2.option
group by t1.id, t1.name, t2.option, t2.value
ORDER BY t1.id, t1.name
4

4 回答 4

8

您必须使用从第一个表和第二个表CROSS JOIN中获取所有可能的组合。然后将这些与第二张表结合起来。就像是:nameoptionLEFT JOIN

SELECT 
  t1.id,
  t1.name,
  t2.option,
  t2.value
FROM
(
  SELECT t1.id, t1.name, t2.option
  FROM table1 AS t1
  CROSS JOIN table2 AS t2
) AS t1
LEFT JOIN table2 AS t2  ON t1.id = t2.tbl1_fk
                       AND t1.option = t2.option

SQL 小提琴演示

于 2013-03-25T12:53:21.977 回答
3

简单版:选项=组

它没有在 Q 中指定,但似乎选项应该以某种方式定义一个组。在这种情况下,查询可以简单地是:

SELECT t1.id, t1.name, t2.option, t2.value
FROM  (SELECT generate_series(1, max(option)) AS option FROM table2) o
CROSS  JOIN table1 t1
LEFT   JOIN table2 t2 ON t2.option = o.option AND t2.tbl1_fk = t1.id
ORDER  BY o.option, t1.id;

或者,如果选项没有按顺序编号,则从 开始1

...
FROM  (SELECT DISTINCT option FROM table2) o
...

回报:

 id | name  | option | value
----+-------+--------+-------
  1 | one   |      1 |     1
  2 | two   |      1 |     1
  3 | three |        |
  1 | one   |      2 |     1
  2 | two   |        |
  3 | three |      2 |     1
  • 更快更干净避免大CROSS JOIN的和大的GROUP BY
  • 您将获得每组带有组号 ( )的不同行。grp
  • 需要 Postgres 8.4+。

更复杂:由行序列指示的组

WITH t2 AS (
   SELECT *, count(step OR NULL) OVER (ORDER BY id) AS grp
   FROM (
      SELECT *, lag(tbl1_fk, 1, 2147483647) OVER (ORDER BY id) >= tbl1_fk AS step
      FROM table2
      ) x
   )
SELECT g.grp, t1.id, t1.name, t2.option, t2.value
FROM  (SELECT generate_series(1, max(grp)) AS grp FROM t2) g
CROSS  JOIN table1 t1
LEFT   JOIN        t2 ON t2.grp = g.grp AND t2.tbl1_fk = t1.id
ORDER  BY g.grp, t1.id;

结果:

 grp | id | name  | option | value
-----+----+-------+--------+-------
   1 |  1 | one   |      1 |     1
   1 |  2 | two   |      1 |     1
   1 |  3 | three |        |
   2 |  1 | one   |      2 |     1
   2 |  2 | two   |        |
   2 |  3 | three |      2 |     1

-> SQLfiddle两者都适用。

如何?

解释复杂的版本...

  • 每组都以tbl1_fk<= 最后一组开始。我用窗口函数lag()检查这个。为了覆盖第一行的极端情况(没有前一行),我提供了最大可能的整数2147483647作为lag().

  • 使用count()聚合窗口函数,我将运行计数添加到每一行,有效地形成组号grp

  • 我可以为每个组获取一个实例:

    (SELECT DISTINCT grp FROM t2) g
    

    但是,获得最大值并generate_series()为减少的CROSS JOIN.

  • CROSS JOIN正好产生了我们需要的行,没有任何多余的。避免了以后的需要GROUP BY

  • LEFT JOIN t2为此,使用grp除了tbl1_fk使其与众不同。

  • 以您喜欢的任何方式排序 - 现在可以使用组号。

于 2013-03-25T19:38:43.433 回答
0

尝试这个

SELECT
  table1.id, table1.name, table2.option, table2.value  FROM table1 AS table11
JOIN table2 AS table2 ON table1.id = table2.tbl1_fk
于 2013-03-25T12:54:10.183 回答
-5

这就够了:

select * from table1 left join table2 on table1.id=table2.tbl1_fk ;

于 2013-11-05T09:42:29.117 回答