我有一个
PostgreSQL
数据库,其中包含食物表和标签表。我需要使用 Python
基于标签从 psycopg3
GUI 查询数据。如果标签参数是空列表,我需要使用食物表中所有餐厅的数据。
如果带有参数 id (
'ids_arg'
) 的某些餐厅具有某些参数标签 ('tags_arg'
),则下面的查询将返回所需的结果。如果 'tags_arg'
列表为空,导致 PostgreSQL 中出现 t.name = ANY (array[]::text[])
,如何查询和计算所有餐厅的数据,无论 id 或标签如何?我可以通过在不带 UNION ALL
的相同查询中添加 INNER JOIN
并根据结果使用结果表的第一行或第二行来获得所需的结果,但这大约使查询字符串文件中的行数增加一倍。考虑到可读性很重要。有没有一种巧妙的方法可以在不使用 UNION ALL
或以其他方式添加大量线条的情况下实现相同的结果?效率分析也将受到赞赏。
SELECT Total, Total - Drinks AS "Without drinks", Drinks
FROM (
SELECT
SUM (f.prepared)
FILTER (
WHERE f.date BETWEEN 'first' AND 'last'
AND f.restaurant_id = ANY ('ids_arg')
) AS Total,
SUM (f.prepared)
FILTER (
WHERE (f.product_id = 10 OR f.product_id = 17)
AND f.date BETWEEN 'first' AND 'last'
AND f.restaurant_id = ANY ('ids_arg')
) AS Drinks
FROM food f
INNER JOIN tags t
ON t.restaurant_id = f.restaurant_id
WHERE t.name = ANY ('tags_arg'::text[])
);
编辑:这是一个 dbfiddle,其中包含
union
查询和 Zegarek 的答案查询。答案查询不会给出相同的结果。
为您的
where
添加适当的条件:
SELECT Total, Total - Drinks AS "Without drinks", Drinks
FROM (
SELECT
SUM (f.prepared)
FILTER (
WHERE f.date BETWEEN 'first' AND 'last'
AND f.restaurant_id = ANY ('ids_arg')
) AS Total,
SUM (f.prepared)
FILTER (
WHERE (f.product_id = 10 OR f.product_id = 17)
AND f.date BETWEEN 'first' AND 'last'
AND f.restaurant_id = ANY ('ids_arg')
) AS Drinks
FROM food f
INNER JOIN tags t
ON t.restaurant_id = f.restaurant_id
WHERE array_position('tags_arg'::text[],t.name) IS NOT null
OR array_length('tags_arg'::text[],1) IS null
);
any(text[])
会产生 null
,无论您的 t.name
是否在 tags_arg
数组中,只要数组中还存在一个或多个 null
,或者 t.name
其本身为空,或两者皆为空。这是因为 any()
使用常规相等 =
运算符,而 array_position()
使用 is not distinct from
构造。
这是一个备忘单:db<>fiddle 的演示
select tags_arg,
tags_arg::text[] as_array,
'tag1'=any(tags_arg::text[]) as "base",
'tag1'=any(coalesce(tags_arg::text[],array['tag1']::text[])) as "+coalesce()",
'tag1'=any(coalesce(tags_arg::text[],array['tag1']::text[]))
OR array_length(tags_arg::text[],1) is null as "+coalesce()+OR",
'tag1'=any(coalesce(tags_arg::text[],array['tag1']::text[]))
OR array_length(tags_arg::text[],1) is null
OR array_position(tags_arg::text[],null) is not null as "+coalesce()+OR+nullsafe",
array_position(tags_arg::text[],'tag1') is not null
OR array_length(tags_arg::text[],1) is null as "final"
from (values ('{tag1,tag2,tag3}') --matching array
,('{tag4,tag5}') --non-matching array
,('{tag6,null}') --non-matching with a null
,('{null}') --only a null
,('{}') --empty
,(null) ) as args(tags_arg);
tags_arg | as_array | 基地 | +合并() | +合并()+OR | +合并()+OR+nullsafe | 决赛 |
---|---|---|---|---|---|---|
{标签1,标签2,标签3} | {标签1,标签2,标签3} | T | T | T | T | T |
{标签4,标签5} | {标签4,标签5} | f | f | f | f | f |
{标签6,空} | {标签6,NULL} | 空 | 空 | 空 | T | f |
{空} | {空} | 空 | 空 | 空 | T | f |
{} | {} | f | f | T | T | T |
空 | 空 | 空 | T | T | T | T |