我有以下代码,使用pscyopg2:
sql = 'select %s from %s where utctime > %s and utctime < %s order by utctime asc;'
data = (dataItems, voyage, dateRangeLower, dateRangeUpper)
rows = cur.mogrify(sql, data)
这种输出:
select 'waterTemp, airTemp, utctime' from 'ss2012_t02' where utctime > '2012-05-03T17:01:35+00:00'::timestamptz and utctime < '2012-05-01T17:01:35+00:00'::timestamptz order by utctime asc;
当我执行这一点,倒了 - 这是可以理解的,因为周围的表名引号是非法的。
有没有办法合法地通过表名作为参数,或做我需要做一个(明确警告反对)字符串连接,即:
voyage = 'ss2012_t02'
sql = 'select %s from ' + voyage + ' where utctime > %s and utctime < %s order by utctime asc;'
干杯的任何见解。
Answer 1:
表名称不能作为参数传递,但一切可以。 因此,表名应该很难在你的应用程序编码(不要把输入或使用任何程序之外的名称)。 你的代码应该工作了这一点。
在你有正当理由采取外部表名轻微的机会,请确保您不允许用户直接输入它。 也许指数可以通过选择表或表名称可能会在一些其他的方式进行查找。 你是正确的警惕这样做的,但是。 这工作,因为周围有相对较少的表名。 找到一个方法来验证表的名称,你应该罚款。
这将有可能做这样的事情,看看表名称存在。 这是一个参数化的版本。 只要确保你做到这一点,在运行SQL代码之前验证输出。 的理念,为这部分源于这个答案 。
SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' and table_name=%s LIMIT 1
Answer 2:
根据官方文档:
如果您需要动态生成的SQL查询( 例如动态地选择一个表名 ),你可以使用由psycopg2.sql模块所提供的设施。
该sql
模块在psycopg2 2.7版新。 它的语法如下:
from psycopg2 import sql
cur.execute(
sql.SQL("insert into {} values (%s, %s)")
.format(sql.Identifier('my_table')),
[10, 20])
更多: http://initd.org/psycopg/docs/sql.html#module-psycopg2.sql
[更新2017年3月24日: AsIs
不应该被用来表示表或字段名称,新的sql
模块应该使用: https://stackoverflow.com/a/42980069/5285608 ]
另外,根据psycopg2文档:
警告 :永远, 永远 , 永远不要使用Python字符串连接( +
)或字符串参数插值( %
)将变量传递给一个SQL查询字符串。 甚至在枪口下。
Answer 3:
每这个答案 ,你可以做到这一点像这样:
import psycopg2
from psycopg2.extensions import AsIs
#Create your connection and cursor...
cursor.execute("SELECT * FROM %(table)s", {"table": AsIs("my_awesome_table")})
Answer 4:
我已经创建了一个与变量表(...)名的SQL语句的预处理一个小工具:
from string import letters
NAMECHARS = frozenset(set(letters).union('.'))
def replace_names(sql, **kwargs):
"""
Preprocess an SQL statement: securely replace table ... names
before handing the result over to the database adapter,
which will take care of the values.
There will be no quoting of names, because this would make them
case sensitive; instead it is ensured that no dangerous chars
are contained.
>>> replace_names('SELECT * FROM %(table)s WHERE val=%(val)s;',
... table='fozzie')
'SELECT * FROM fozzie WHERE val=%(val)s;'
"""
for v in kwargs.values():
check_name(v)
dic = SmartDict(kwargs)
return sql % dic
def check_name(tablename):
"""
Check the given name for being syntactically valid,
and usable without quoting
"""
if not isinstance(tablename, basestring):
raise TypeError('%r is not a string' % (tablename,))
invalid = set(tablename).difference(NAMECHARS)
if invalid:
raise ValueError('Invalid chars: %s' % (tuple(invalid),))
for s in tablename.split('.'):
if not s:
raise ValueError('Empty segment in %r' % tablename)
class SmartDict(dict):
def __getitem__(self, key):
try:
return dict.__getitem__(self, key)
except KeyError:
check_name(key)
return key.join(('%(', ')s'))
该SmartDict对象返回%(key)s
每一个未知key
,保存它们的值处理。 该功能可以检查没有任何引号字符,因为所有引用的现在应该被照顾...
Answer 5:
如果你想通过表名作为参数,你可以用这个包装:
class Literal(str):
def __conform__(self, quote):
return self
@classmethod
def mro(cls):
return (object, )
def getquoted(self):
return str(self)
用法: cursor.execute("CREATE TABLE %s ...", (Literal(name), ))
Answer 6:
这是我在过去使用的解决方法
query = "INSERT INTO %s (col_1, col_2) VALUES (%%s, %%s)" % table_name
cur.execute(query, (col_1_var, col_2_var))
希望它能帮助:)
Answer 7:
你可以使用该模块格式表名,然后使用常规paramaterization的执行:
xlist = (column, table)
sql = 'select {0} from {1} where utctime > %s and utctime < %s order by utctime asc;'.format(xlist)
请记住,如果这是暴露给最终用户,您将无法从SQL注入,除非你写它的保护。
Answer 8:
没有人感到惊讶提到这样做:
sql = 'select {} from {} where utctime > {} and utctime < {} order by utctime asc;'.format(dataItems, voyage, dateRangeLower, dateRangeUpper)
rows = cur.mogrify(sql)
格式会将字符串中没有报价。
文章来源: Passing table name as a parameter in psycopg2