在WHERE IN()或SELECT和LEFT JOIN

时间:2017-03-20 22:55:26

标签: sql postgresql outer-join postgresql-9.5

我有那样的表:

 table:
 | id | fkey | label | amount |
 |----|------|-------|--------|
 | 1  | 1    | aaa   | 10     |
 | 2  | 1    | bbb   | 15     |
 | 3  | 1    | fff   | 99     |
 | 4  | 1    | jjj   | 33     |
 | 5  | 2    | fff   | 10     |

fkey是其他表的外键。

现在我需要查询与某些标签相关的所有金额(' bbb',' eee' fff')和指定的fkey,但是我需要使用NULL保留所有未标记的标签。

对于WHERE IN ('bbb', 'eee', 'fff')的简单查询,我当然只有两行:

 SELECT label, amount FROM table WHERE label IN ('bbb', 'eee', 'fff') AND fkey = 1;

 | label | amount |
 |-------|--------|
 | bbb   | 15     |
 | fff   | 99     |

但例外结果应为:

 | label | amount |
 |-------|--------|
 | bbb   | 15     |
 | eee   | NULL   |
 | fff   | 99     |

我还尝试了SELECT label UNION ALL label (...) LEFT JOIN,它应该适用于MySQL(Keep all records in "WHERE IN()" clause, even if they are not found):

  SELECT T.label, T.amount FROM (
    SELECT 'bbb' AS "lbl"
    UNION ALL 'eee' AS "lbl"
    UNION ALL 'fff' AS "lbl"
  ) LABELS
  LEFT OUTER JOIN table T ON (LABELS."lbl" = T."label")
  WHERE T.fkey = 1;

以及WITH声明:

  WITH LABELS AS (
    SELECT 'bbb' AS "lbl"
    UNION ALL 'eee' AS "lbl"
    UNION ALL 'fff' AS "lbl"
  )
  SELECT T.label, T.amount FROM LABELS
  LEFT OUTER JOIN table T ON (LABELS."lbl" = T."label")
  WHERE T.fkey = 1;

但总是这个LEFT JOIN给我2行istead 3.

创建临时表根本不起作用(我从中得到0行,我不能在连接中使用它):

 CREATE TEMPORARY TABLE __ids (
   id VARCHAR(9) PRIMARY KEY
 ) ON COMMIT DELETE ROWS;

 INSERT INTO __ids (id) VALUES
   ('bbb'),
   ('eee'),
   ('fff');

 SELECT
   *
 FROM __ids

知道如何强制Postgres保持空关系吗?或者甚至是任何其他想法来获得标签' eee'如果表中没有这个行,那么是否为NULL?

每个请求的标签列表都可以不同。

此案例在线:http://rextester.com/CRQY46630

------编辑----- 我用过滤器where扩展了这个问题,因为来自a_horse_with_no_name的回答非常好,但不能涵盖我的整个案例(无论如何我都认为这个where

1 个答案:

答案 0 :(得分:3)

您使用外部联接的方法有效。您只需要从"外部"中获取标签值。加入表格,而不是来自"表格":

with labels (lbl) as (
  values ('bbb'), ('eee'), ('fff')
)
select l.lbl,  --<< this is different to your query
       t.amount 
from labels l 
  left outer join "table" t on l.lbl = t.label;

在线示例:http://rextester.com/LESK82163

问题范围扩大后,

编辑

如果要在基表上进行过滤,则需要移入JOIN条件,而不是where子句:

with labels (lbl) as (
  values ('bbb'), ('eee'), ('fff')
)
select l.lbl,  --<< this is different to your query
       t.amount 
from labels l 
  left outer join "table" t 
               on l.lbl = t.label
              and t.fkey = 1; --<< 

在线示例:http://rextester.com/XDO76971