在 PostgreSQL 中以列表作为参数进行选择,如果为空则选择不带参数

问题描述 投票:0回答:1

我有一个

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 的答案查询。答案查询不会给出相同的结果。

sql postgresql select conditional-statements arguments
1个回答
1
投票

为您的

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
© www.soinside.com 2019 - 2024. All rights reserved.