psycopg3 动态 sql.带别名/标签的标识符

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

我试图解决的问题是从 JSON 字段获取

feature
数据,以便保留结果列名称。这意味着尝试了解是否有更好和/或更安全的方法来使用 psycopg(3) 动态定义列别名。

我目前已实施以下解决方案:

# imports
import psycopg
from psycopg import Connection, sql
from psycopg.rows import dict_row

# constants
project = "project_1"
location = "location_1"
data_table = "table_1"
features = ["feature_1", "feature_2"]
start_dt = "2024-04-22T16:00:00"
end_dt = "2024-04-22T17:00:00"

__user = "My"
__password = "I am supposed to be extra-complicated!"
__host = "localhost"
__database = "db"
__port = 5432

# connection
connection = psycopg.connect(
    user=__user,
    password=__password,
    host=__host,
    dbname=__database,
    port=__port,
    row_factory=dict_row,
)

# Adapted from https://github.com/psycopg/psycopg2/issues/791#issuecomment-429459212
def alias_identifier(
    ident: str | tuple[str], alias: str | None = None
) -> sql.Composed:
    """Return a SQL identifier with an optional alias."""
    if isinstance(ident, str):
        ident = (ident,)
    if not alias:
        return sql.Identifier(*ident)
    # fmt: off
    return sql.Composed([sql.Literal(*ident), sql.SQL(" AS "),
                         sql.Identifier(alias)])
    # fmt: on

# source query str
QUERY = """SELECT
    current_database() AS project,
    timestamp,
    location,
    feature -> {feature}
FROM {data_table}
WHERE lower(location) = {location}
AND timestamp BETWEEN {start_dt} AND {end_dt}
"""

# SQL query
query = sql.SQL(QUERY).format(
    feature=sql.SQL(", feature -> ").join([alias_identifier(m, alias=m) for m in features]),
    data_table=sql.Identifier(data_table),
    location=sql.Literal(location),
    start_dt=sql.Literal(start_dt),
    end_dt=sql.Literal(end_dt),
)


print(query.as_string(connection))
SELECT
    current_database() AS project,
    timestamp,
    location,
    feature -> 'feature_1' AS "feature_1", feature -> 'feature_2' AS "feature_2"
FROM "table_1"
WHERE lower(location) = 'location_1'
AND timestamp BETWEEN '2024-04-22T16:00:00' AND '2024-04-22T17:00:00'

该解决方案提供了预期的结果,尽管我想知道它是否违反了任何 psycopg 指南以及是否有更好的方法来实现我想要的。

python sql postgresql psycopg2 psycopg3
1个回答
0
投票

在我的用法中我这样做:

... WHERE lower(location) = %(location)s
AND timestamp BETWEEN %(start_dt)s AND %(end_dt)s

然后做:


cur.execute(query, {"location": location , "start_dt": start_date, "end_date": end_dt:})


© www.soinside.com 2019 - 2024. All rights reserved.