0

如果提供了空列表作为参数,我想将 IN 语句作为我的 sql 查询的可选部分,但未能提供。我可以做解决方法并在代码中使用一些默认值而不是空列表(所有 cam_ids),但我想知道如何正确地做到这一点。

我有以下 sql 表达式(实际表达式要长得多):

SELECT 
 id, cam_id
 FROM sometable
 WHERE id > %(_id)s
 // if use = instead of IN, it works well (of course if cameras is just one value, not array)
 AND (%(camera)s is NULL OR cam_id IN %(camera)s)  

在 python 中,我通过以下方式为查询提供了参数:

values = {"_id": 10, camera: tuple(1, 2, 3)]}
curs.execute(query, values)

如果元组不为空,则一切正常,否则:

如果相机 = 无,我收到以下错误:

psycopg2.errors.SyntaxError:“NULL”处或附近的语法错误第 6 行:WHERE(NULL 为 NULL 或 cam_id IN NULL)

如果 camera = tuple(),我得到以下错误:

psycopg2.errors.SyntaxError:“)”处或附近的语法错误第 6 行:WHERE (() 为 NULL 或 cam_id IN ())

为了更清楚:

如果提供了空数组,我想获得所有可能的 cam_ids的所有结果,因此结果应该与SELECT * FROM tablename;

编辑:莫里斯·迈耶

我在尝试进行更大的查询时发现了以下问题

select * from vworker_tracks
where
    // still need some default value: cam_id != ''
    (cam_id = any('{}') or cam_id != '') 
and
    // unexpected results when both are true, provides all tracks  > 0.0
    (track_duration_seconds = 2.5 or track_duration_seconds > 0.0) 
and 
    id < 100

order by id desc limit 10;
4

3 回答 3

1

您可以OR在您的WHERE条件下使用“模仿” if/else

query = """
with cameras as (
    select
        %(ids)s::int[] as ids,
        %(idsLen)s as count /* simplify */
)
select
count(conversations.*)
from
conversations,
cameras
where
(
(cameras.count >= 1 and id = ANY(cameras.ids))
or
(cameras.count < 1 and id > %(_id)s)
)
"""

for ids in [[81, 60], []]:
    values = {"_id": 10, "ids": ids, "idsLen": len(ids)}
    curs.execute(query, values)
    print(curs.fetchone())

出去:

(2,)    # 2 ids given, returns 2 records
(118,)  # empty array, returns ALL records
于 2021-05-17T23:32:10.483 回答
0

您可以在 PostgreSQL 中使用=ANY(),其中 ANY 将数组作为输入。而且那个数组可以是空的,没问题。简单示例:

SELECT  1 = ANY('{}') -- false
    ,   2 = ANY('{2,3,4}'); -- true
于 2021-05-17T19:06:30.997 回答
0

答案没有提供任何原生 sql 解决方案,它基于https://use-the-index-luke.com/sql/myth-directory/dynamic-sql-is-slow,遵循 KISS 原则:

from aiopg.cursor import Cursor


async def my_test_query(curs: Cursor, params: dict) -> list:
    """
    the snippet demonstrates how to create IN filters
    The idea is build on the article
    https://use-the-index-luke.com/sql/myth-directory/dynamic-sql-is-slow
    follows KISS principle
    """
    query = f"""
        SELECT 
          id,
          cam_id,
          track_duration_seconds,  
          top_color, 
          bottom_color,
          crossed_lines->>'entrance',
          crossed_lines->>'cross_direction'
        FROM vworker_tracks 
        WHERE id < %(_id)s
    """
    if params.get("camera", None) is not None:
        query += " AND cam_id IN %(camera)s"

    if params.get("bottom_color", None) is not None:
        query += " AND bottom_color IN %(bottom_color)s"

    if params.get("top_color", None) is not None:
        query += " AND top_color IN %(top_color)s"

    if params.get("cross_direction", None) is not None:
        query += " AND crossed_lines->>'cross_direction' IN %(cross_direction)s"

    if params.get("entrance", None) is not None:
        query += " AND crossed_lines->>'entrance' IN %(entrance)s"

    query += " ORDER BY id DESC LIMIT 50;"

    await curs.execute(query, params)
    res = await curs.fetchall()
    return res
于 2021-05-20T11:48:28.153 回答