我有一个问题要设计一个好的算法,该算法使用此处描述的psycopg2库的规范
我想建立一个与该字符串相等的动态查询:
SELECT ST_GeomFromText('POLYGON((0.0 0.0,20.0 0.0,20.0 20.0,0.0 20.0,0.0 0.0))');
如您所见,我的POLYGON对象包含多个点,请读取一个简单的csv文件some.csv,其中包含:
0.0;0.0 20.0;0.0 20.0;20.0 0.0;20.0 0.0;0.0
所以我动态地建立查询,在CSV功能行/数据的数量。
在这里,我的程序生成要执行的SQL查询字符串:
import psycopg2 import csv # list of points lXy = [] DSN= "dbname='testS' user='postgres' password='postgres' host='localhost'" conn = psycopg2.connect(DSN) curs = conn.cursor() def genPointText(curs,x,y): generatedPoint = "%s %s" % (x,y) return generatedPoint #Lecture fichier csv polygonFile = open('some.csv', 'rb') readerCSV = csv.reader(polygonFile,delimiter = ';') for coordinates in readerCSV: lXy.append(genPointText(curs,float(coordinates[0]),float(coordinates[1]))) # function of list concatenation by separator def convert(myList,separator): return separator.join([str(i) for i in myList]) # construct simple query with psycopg def genPolygonText(curs,l): # http://initd.org/psycopg/docs/usage.html#python-types-adaptation generatedPolygon = "POLYGON((%s))" % convert(l, ",") return generatedPolygon def executeWKT(curs,geomObject,srid): try: # geometry ST_GeomFromText(text WKT, integer srid); finalWKT = "SELECT ST_GeomFromText('%s');" % (geomObject) print finalWKT curs.execute(finalWKT) except psycopg2.ProgrammingError,err: print "ERROR = " , err polygonQuery = genPolygonText(curs,lXy) executeWKT(curs,polygonQuery,4326)
如您所见,这是可行的,但是由于python对象和sql postgresql对象之间的转换问题,这种方式是不正确的。
在文档中,我仅看到为静态查询提供和转换数据的示例。您是否知道在动态构建查询中以正确类型创建正确字符串的“优雅”方式?
更新1:
如您所见,当我在此简单示例上使用psycopg类型转换函数时,出现如下错误:
query = "ST_GeomFromText('POLYGON(( 52.146542 19.050557, 52.148430 19.045527, 52.149525 19.045831, 52.147400 19.050780, 52.147400 19.050780, 52.146542 19.050557))',4326)" name = "my_table" try: curs.execute('INSERT INTO %s(name, url, id, point_geom, poly_geom) VALUES (%s);', (name,query)) except psycopg2.ProgrammingError,err: print "ERROR = " , err
误差相等:
ERROR = ERREUR: erreur de syntaxe sur ou près de « E'my_table' » LINE 1: INSERT INTO E'my_table'(name, poly_geom) VALUES (E'ST_GeomFr...
更新2:
最终代码可以工作,这要感谢stackoverflow用户!
#info lib : http://www.initd.org/psycopg/docs/ import psycopg2 # info lib : http://docs.python.org/2/library/csv.html import csv # list of points lXy = [] DSN= "dbname='testS' user='postgres' password='postgres' host='localhost'" print "Opening connection using dns:", DSN conn = psycopg2.connect(DSN) curs = conn.cursor() def genPointText(curs,x,y): generatedPoint = "%s %s" % (x,y) return generatedPoint #Lecture fichier csv polygonFile = open('some.csv', 'rb') readerCSV = csv.reader(polygonFile,delimiter = ';') for coordinates in readerCSV: lXy.append(genPointText(curs,float(coordinates[0]),float(coordinates[1]))) # function of list concatenation by separator def convert(myList,separator): return separator.join([str(i) for i in myList]) # construct simple query with psycopg def genPolygonText(l): # http://initd.org/psycopg/docs/usage.html#python-types-adaptation generatedPolygon = "POLYGON((%s))" % convert(l, ",") return generatedPolygon def generateInsert(curs,tableName,name,geomObject): curs.execute('INSERT INTO binome1(name,geom) VALUES (%s, %s);' , (name,geomObject)) def create_db_binome(conn,name): curs = conn.cursor() SQL = ( "CREATE TABLE %s" " (" " polyname character varying(15)," " geom geometry," " id serial NOT NULL," " CONSTRAINT id_key PRIMARY KEY (id)" " )" " WITH (" " OIDS=FALSE" " );" " ALTER TABLE %s OWNER TO postgres;" ) %(name,name) try: #print SQL curs.execute(SQL) except psycopg2.ProgrammingError,err: conn.rollback() dropQuery = "ALTER TABLE %s DROP CONSTRAINT id_key; DROP TABLE %s;" % (name,name) curs.execute(dropQuery) curs.execute(SQL) conn.commit() def insert_geometry(polyname,tablename,geometry): escaped_name = tablename.replace('""','""') try: test = 'INSERT INTO %s(polyname, geom) VALUES(%%s, ST_GeomFromText(%%s,%%s))' % (escaped_name) curs.execute(test, (tablename, geometry, 4326)) conn.commit() except psycopg2.ProgrammingError,err: print "ERROR = " , err ################ # PROGRAM MAIN # ################ polygonQuery = genPolygonText(lXy) srid = 4326 table = "binome1" create_db_binome(conn,table) insert_geometry("Berlin",table,polygonQuery) insert_geometry("Paris",table,polygonQuery) polygonFile.close() conn.close()
您试图将表名作为参数传递。如果仅查看PostgreSQL错误日志,您可能会立即看到。
您试图通过psycopg2作为参数转义的表名,将产生如下查询:
INSERT INTO E'my_table'(name, url, id, point_geom, poly_geom) VALUES (E'ST_GeomFromText(''POLYGON(( 52.146542 19.050557, 52.148430 19.045527, 52.149525 19.045831, 52.147400 19.050780, 52.147400 19.050780, 52.146542 19.050557))'',4326)');'
这不是您的意图,将无法正常工作;您无法转义像文字一样的表名。您必须使用普通的Python字符串插值来构造动态SQL,只能将参数化的语句占位符用于实际文字值。
params = ('POLYGON(( 52.146542 19.050557, 52.148430 19.045527, 52.149525 19.045831, 52.147400 19.050780, 52.147400 19.050780, 52.146542 19.050557))',4326) escaped_name = name.replace('"",'""') curs.execute('INSERT INTO "%s"(name, url, id, point_geom, poly_geom) VALUES (ST_GeomFromText(%%s,%%s));' % escaped_name, params)
查看我如何直接对名称进行插值以产生查询字符串:
INSERT INTO my_table(name, url, id, point_geom, poly_geom) VALUES (ST_GeomFromText(%s,%s));
(通过%替换%%转换为纯%文本)。然后,我将该查询与定义thePOLYGON和另一个参数ST_GeomFromText作为查询参数的字符串一起使用。
%%
%
POLYGON
ST_GeomFromText
我尚未对此进行测试,但是它应该为您提供正确的想法并帮助您解释问题所在。
*像这样进行字符串插值时要 *格外小心 ,这是SQL注入的简便方法。我已经在上面显示的代码中做了非常粗略的引用,但是如果您的客户端库提供了一个标识符引用功能,我想使用一个适当的标识符引用功能。