使用两个IN()保持空值

时间:2014-11-24 10:05:38

标签: arrays postgresql join

我正在重构非常旧的代码。目前,PHP为每个值生成一个单独的选择。说loc包含12data包含ab,它会生成

select val from tablename where loc_id=1 and data_id=a;
select val from tablename where loc_id=1 and data_id=b;
select val from tablename where loc_id=2 and data_id=a;
select val from tablename where loc_id=2 and data_id=b;

...等等都返回单个值或什么都不返回。这意味着我总是有n(loc_id)* n(data_id)结果,包括空值,这是后续处理所必需的。知道顺序,这用于生成HTML表。理论上,data_id和loc_id都可以扩展到几千(表中显然不是很好,但这是另一个问题)。

           +-----------+-----------+
           | data_id 1 | data_id 2 |
+----------+-----------+-----------+
| loc_id 1 |     -     |  999.99   |
+----------+-----------+-----------+
+ loc_id 2 |   888.88  |     -     |
+----------+-----------+-----------+

为了加快速度,我想用一个查询替换它:

select val from tablename where loc_id in (1,2) and data_id in (a,b) order by loc_id asc, data_id asc;

得到像(下面)的结果并迭代来构建我的表。

Rownum  VAL
------- --------
1       null
2       999.99
3       777.77
4       null

不幸的是,这种方法会从结果集中删除空值,所以我最终得到了

Rownum  VAL
------- --------
1       999.99
2       777.77

请注意,data_id或loc_id可能都没有匹配,在这种情况下我仍然需要null, null

所以我不知道哪个值匹配哪个。如果我添加loc_id和data_id,我可以在php中匹配预期的loc_id / data_id组合......但是这样会变得混乱。

一般来说仍然是SQL的新手,这绝对是我第一次使用PostgreSQL,所以希望这不太明显......当我发布这篇文章时,我正在寻找两种方法来解决这个问题:any in array[]join秒。如果发现任何新内容,将更新。

tl;博士问题

我如何做where loc_id in (1,2) and data_id in (a,b)并保留空值,以便我总是得到n(loc)* n(数据)结果?

3 个答案:

答案 0 :(得分:1)

where (loc_id in (1,2) or loc_id is null)
and  (data_id in (a,b) or data_id is null)

答案 1 :(得分:1)

您可以通过两个步骤在单个查询中实现此目的:

  1. 在输出中生成所有所需行的矩阵。
  2. LEFT [OUTER] JOIN到实际行。
  3. 您的表格中的每个单元格都会至少一行 如果(loc_id, data_id)是唯一的,则完全一行。

    SELECT t.val
    FROM        (VALUES (1), (2))     AS l(loc_id)
    CROSS  JOIN (VALUES ('a'), ('b')) AS d(data_id) -- generate total grid of rows
    LEFT   JOIN tablname t USING (loc_id, data_id) -- attach matching rows (if any)
    ORDER  BY l.loc_id, d.data_id;
    

    适用于任何列数任何值的列。

    对于你的简单案例:

    SELECT t.val
    FROM  (
       VALUES
          (1, 'a'), (1, 'b')
        , (2, 'a'), (2, 'b')
       ) AS ld (loc_id, data_id) -- total grid of rows
    LEFT   JOIN tablname t USING (loc_id, data_id) -- attach matching rows (if any)
    ORDER  BY ld.loc_id, ld.data_id;
    

答案 2 :(得分:0)

选择用于过滤的字段,以便了解值的来源:

select loc,data,val from tablename where loc in (1,2) and data in (a,b);

你也不会以这种方式获得null,但它不再是问题了。您知道缺少哪些字段,并且您知道这些字段是null