结果在where子句中的PostgreSQL用例

时间:2015-04-16 05:29:26

标签: sql postgresql case

我使用复杂的CASE WHEN来选择值。我想在WHERE子句中使用这个结果,但Postgres说列'd'不存在。

SELECT id, name, case when complex_with_subqueries_and_multiple_when END AS d
FROM table t WHERE d IS NOT NULL
LIMIT 100, OFFSET 100;

然后我想我可以这样使用它:

select * from (
    SELECT id, name, case when complex_with_subqueries_and_multiple_when END AS d
    FROM table t 
    LIMIT 100, OFFSET 100) t
WHERE d IS NOT NULL;

但是现在我没有得到100行。可能(我不确定)我可以在select case case语句之外使用LIMIT和OFFSET(其中WHERE语句是),但我认为(我不确定为什么)这会影响性能。

Case返回数组或null。如果case语句的结果为null,那么排除某些行的最佳/最快方法是什么?我需要100行(如果不存在则更少 - 当然)。我正在使用Postgres 9.4。

编辑:

SELECT count(*) OVER() AS count, t.id, t.size, t.price, t.location, t.user_id, p.city, t.price_type, ht.value as houses_type_value, ST_X(t.coordinates) as x, ST_Y(t.coordinates) AS y, 
CASE WHEN t.classification='public' THEN 
ARRAY[(SELECT i.filename FROM table_images i WHERE i.table_id=t.id ORDER BY i.weight ASC LIMIT 1), t.description] 
WHEN t.classification='protected' THEN 
ARRAY[(SELECT i.filename FROM table_images i WHERE i.table_id=t.id ORDER BY i.weight ASC LIMIT 1), t.description]
WHEN t.id IN (SELECT rl.table_id FROM table_private_list rl WHERE rl.owner_id=t.user_id AND rl.user_id=41026) THEN 
ARRAY[(SELECT i.filename FROM table_images i WHERE i.table_id=t.id ORDER BY i.weight ASC LIMIT 1), t.description]
ELSE null
END AS main_image_description
FROM table t LEFT JOIN table_modes m ON m.id = t.mode_id 
LEFT JOIN table_types y ON y.id = t.type_id 
LEFT JOIN post_codes p ON p.id = t.post_code_id 
LEFT JOIN table_houses_types ht on ht.id = t.houses_type_id 
WHERE datetime_sold IS NULL AND datetime_deleted IS NULL AND t.published=true AND coordinates IS NOT NULL AND coordinates && ST_MakeEnvelope(17.831490030182, 44.404640972306, 12.151558389557, 47.837396630872) AND main_image_description IS NOT NULL
GROUP BY t.id, m.value, y.value, p.city, ht.value ORDER BY t.id LIMIT 100 OFFSET 0

1 个答案:

答案 0 :(得分:3)

要在WHERE子句中使用CASE WHEN结果,您需要将其包装在子查询中,就像您一样或在视图中。

SELECT * FROM (
    SELECT id, name, CASE 
        WHEN name = 'foo' THEN true
        WHEN name = 'bar' THEN false
        ELSE NULL
        END AS c
    FROM case_in_where
) t WHERE c IS NOT NULL

使用包含1,'foo',2,'bar',3,'baz'的表格,这将返回记录1& 2.我不知道这个SQL小提琴将持续多久,但这里有一个例子:http://sqlfiddle.com/#!15/1d3b4/3。另请参阅https://stackoverflow.com/a/7950920/101151

如果从偏移量100开始的那100行包含d计算为NULL的记录,则您的限制返回少于100行。我不知道如何限制子选择而不包括你的限制逻辑(你的case语句)重写为在where子句内工作。

WHERE ... AND (
    t.classification='public' OR t.classification='protected'
    OR t.id IN (SELECT rl.table_id ... rl.user_id=41026))

您编写它的方式会有所不同,让CASE逻辑与WHERE限制语句保持同步可能会很烦人,但它会使您的限制仅适用于匹配数据。