You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL中含空格字符串作为SQL变量的.format()用法问题

在PostgreSQL中处理含空格字符串变量的SQL查询问题

问题场景

我使用.format()方法拼接SQL查询时,遇到含空格的字符串变量触发语法错误,代码如下:

data   = "something with white space"
choice = "DESC"
limit  = 10 

def rDB(sql_request):
    with connection.cursor() as cursor:
        cursor.execute(sql_request)
        row = cursor.fetchall()
    return row

def queryWithFormat(data, choice, limit):
    return('''
           SELECT col1, SUM(col2) as nb
           FROM Table
           WHERE col1 = {d}
           GROUP BY col1 
           ORDER BY nb {c}
           LIMIT {l}
           '''.format(d=data, c=choice, l=limit))

rDB(queryWithFormat(data, choice, limit))

报错信息

django.db.utils.ProgrammingError: ERROR: syntax error on or near 'with'
LINE 8: WHERE col1 = something with white ...
-------------------------------^

我尝试了一种解决方案,但不确定是否合规:

  • 拆分SQL请求
  • 使用.format()处理排序方向("DESC"/"ASC")
  • 使用%s处理含空格的字符串

对应代码:

def requeteDB(sql_request):
    with connection.cursor() as cursor:
        cursor.execute(*sql_request)
        row = cursor.fetchall()
    return row

def queryWithFormat(data, choice, limit):
    return('''
           SELECT col1, SUM(col2) as nb
           FROM Table
           WHERE col1 = %s
           GROUP BY col1 
           ORDER BY nb {0}
           LIMIT %s
           '''.format(choice), [data,limit])

希望确认该方案是否合规,或获取正确的实现方式。


方案验证与正确实践

你尝试的方案合规性说明

你用%s做参数绑定、.format()处理排序方向的思路是合规且安全的,但有两个细节需要优化:

  1. 排序方向(DESC/ASC)属于SQL语法关键字,用.format()时必须做合法性校验,避免SQL注入风险
  2. 可以调整写法更贴合Django的参数化查询规范

优化后的正确实现

方式1:原生SQL参数化查询(推荐)

利用Django cursor的参数绑定能力,同时对排序方向做白名单校验:

data   = "something with white space"
choice = "DESC"
limit  = 10 

def rDB():
    # 校验排序方向合法性,只允许ASC/DESC
    if choice not in ("ASC", "DESC"):
        raise ValueError("无效的排序方向,仅支持ASC或DESC")
    
    with connection.cursor() as cursor:
        # %s作为参数占位符,参数列表传入execute第二个参数
        cursor.execute('''
            SELECT col1, SUM(col2) as nb
            FROM "Table"
            WHERE col1 = %s
            GROUP BY col1 
            ORDER BY nb {}
            LIMIT %s
        '''.format(choice), [data, limit])
        row = cursor.fetchall()
    return row

rDB()

方式2:使用Django ORM(更推荐)

如果业务允许,用ORM替代原生SQL能大幅提升安全性和可维护性:

from django.db.models import Sum

data   = "something with white space"
choice = "DESC"
limit  = 10 

# 校验排序方向
if choice not in ("ASC", "DESC"):
    raise ValueError("无效的排序方向")

# ORM实现等价查询
result = (
    Table.objects.filter(col1=data)
    .values("col1")
    .annotate(nb=Sum("col2"))
    .order_by("-nb" if choice == "DESC" else "nb")
    .values_list("col1", "nb")
    [:limit]
)

核心注意事项

  • 禁止用.format()直接拼接用户输入的字符串参数:既会引发含空格字符串的语法错误,还存在严重的SQL注入风险
  • SQL关键字(如排序方向)用.format()时必须做白名单校验:只允许预设的合法值,杜绝注入可能
  • 数值类型参数(如limit):优先用参数绑定,保持写法统一

内容的提问来源于stack exchange,提问作者problème0123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 11:46:04