Python语法:Subprocess调用PostgreSQL查询,"错误:只允许ASCII字符"

Dan*_*iel 5 python postgresql subprocess postgresql-9.3

我在python中使用以下代码,调用PostgreSQL查询subprocess:

import subprocess
claimer_name = 'a_name'
startdate = '2014-04-01'
enddate = '2018-04-01' 

data = subprocess.check_output(['/usr/bin/psql -U user_name "SELECT c.asset_id, c.video_id,
c.claim_id, c.claim_date FROM db.claim c JOIN db.claim_history h ON c.claim_id = h.claim_id JOIN
db.users_email e ON LOWER(e.email) = LOWER(h.email) JOIN m.auth_user u ON e.user_id = u.id WHERE
h.list_order = 1 AND c.claim_origin = ‘Descriptive Search’ AND c.claim_date >= \"%s\" AND    
c.claim_date < \"%s\" AND concat(u.first_name, concat(chr(32),
u.last_name)) = \"%s\""' % (startdate, enddate, claimer_name)], shell=True)
Run Code Online (Sandbox Code Playgroud)

如何逃避"描述性搜索"周围的单引号?按原样运行此代码会产生错误Only ASCII characters are allowed in an identifier.

我试过了:

  1. [''Descriptive Search'']
  2. [\'Descriptive Search\']
  3. [""Descriptive Search""]
  4. [concat('Descriptive', concat(chr(32), 'Search'))]

并指定一个变量:i = 'Descriptive Search',然后c.claim_origin = \"%s\".

但是,这些尝试产生相同的ASCII characters错误.使用字符串格式化为我的其他变量正常工作(startdate,enddate,claimer_name),我难倒,为什么它不会为字符串"描述性搜索"工作.

使用PostgreSQL 9.3.

任何正确方向的帮助或要点都会很棒; 谢谢!

Cra*_*ger 6

这有很多问题.

  • 您应该使用psycopg2而不是尝试shell psql来与数据库通信;

  • 因为您没有使用正确的数据库绑定,所以无法正确使用放置参数(预处理语句),因此您必须自己处理文本中的转义以避免SQL注入风险并引用错误;

  • 在通过调用命令时subprocess,尽可能避免使用shell.这是可能失败的另一点,在这种情况下完全没有必要;

  • 通常应"""在Python中引用长字符串以避免需要转义嵌套"s;

  • 表达式concat(u.first_name, concat(chr(32), u.last_name))是不必要的扭曲.只写u.first_name || ' ' || u.last_nameformat('%s %s', u.first_name, u.last_name);

  • "double quotes"用来引用替换的文字,这是无效的SQL.根据文档,它们将被视为标识符.所以c.claim_date < \"%s\"会因为错误而失败no column "2014-04-01";

  • 在引用时,您使用的是真正的单引号,而不是撇号‘Descriptive Search‘.猜测你已经在文字处理器中编辑了代码,而不是程序员的文本编辑器.'Descriptive Search'在SQL中引用文字时,您需要撇号.

因为您使用单引号字符(U + 2018)而不是撇号(U + 0027)来引用文字字符串Descriptive Search,PostgreSQL不会将其识别为文字并尝试将其解析为标识符.但是,在不带引号的标识符中不是合法字符,因此它报告了您显示的错误.

请参阅有关标识符和文字的文档.

这是你应该做的:

import psycopg2
import datetime
claimer_name = 'a_name'
startdate = datetime.date(2014, 1, 1)
enddate = datetime.date(2018, 1, 1)

conn = psycopg2.connect("user=user_name")
curs = conn.cursor()
curs.execute("""
    SELECT 
        c.asset_id,
        c.video_id,
        c.claim_id,
        c.claim_date
    FROM db.claim c 
         JOIN db.claim_history h ON c.claim_id = h.claim_id 
         JOIN db.users_email e ON LOWER(e.email) = LOWER(h.email) 
         JOIN m.auth_user u ON e.user_id = u.id 
    WHERE h.list_order = 1 
      AND c.claim_origin = 'Descriptive Search'
      AND c.claim_date >= %s 
      AND c.claim_date < %s
      AND u.first_name || ' ' || u.last_name = %s
    """, (startdate, enddate, claimer_name)
)
results = curs.fetchall()
Run Code Online (Sandbox Code Playgroud)

特别要注意的是,我并没有使用Python的%字符串格式化操作员上方.的%s条目放置参数that're通过psycopg2适当取代; 请参阅将参数传递给SQL查询.