我有一个PostgreSQL的数据库,有一个食物表格和一个标签表格.我需要使用psycopg3根据标签(S)从Python图形用户界面查询数据.如果标记参数是一个空列表,我需要使用来自食物表中所有餐厅的数据.

如果具有参数id(S)('ids_arg')的某些餐馆(S)具有一些参数标记(S)('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[])
);

编辑:以下是包含UNION ALL个问题和Zegarek的回答问题的dbfiddle分.

推荐答案

在你的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
);

这也使它成为零安全的.无论您的t.name是否在tags_arg数组中,只要数组中也存在一个或多个null,或者t.name本身为空,或者两者兼而有之,都是一个常规的any(text[]) yields a null.这是因为any()使用正则相等=运算符,而array_position()使用is not distinct from构造.

这里有一张小抄:demo at 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 base +coalesce() +coalesce()+OR +coalesce()+OR+nullsafe final
{tag1,tag2,tag3} {tag1,tag2,tag3} T T T T T
{tag4,tag5} {tag4,tag5} f f f f f
{tag6,null} {tag6,NULL} null null null T f
{null} {NULL} null null null T f
{} {} f f T T T
null null null T T T T

Sql相关问答推荐

如何通过比较不同表中相同ID S的值来筛选ID为S的列表?

当我们加入两个表时,我们可以省略GROUP BY中的列名吗?

仅 for each 唯一ID返回一个元素,并仅返回最新连接的记录

SQL -滞后于上一个非重复值

Access中执行INSERT INTO查询时出现错误消息

使用SQL数据库中的现有列派生或修改几个列

在SQL中将项分配给容器

VS代码无法识别SQL代码中带括号的字符串

计算不同模式的时间跨度

SQL的左连接在多对多关系情况下使用

自动生成计算频率的列

根据潜在空值的条件对记录进行计数

插入行时的行安全策略问题

postgres按组消除分区中的NULLS

忽略与给定列匹配的行的 LAG 函数

如何从 2 个 SQLite 表构建嵌套对象?

我现在如何显示重复的汽车? postgresql

根据开始/结束标记将 GROUP_ID 分配给行

在 PostgreSQL 中,如何将数组中的每个元素用作另一个表中的键?

Oracle SQL 查询自行运行,但在包装到select count(*) from ()时失败