当前位置: 首页 > 面试题库 >

使用psycopg2 python库并使用良好的转换类型工具构建SQL动态查询

丌官承
2023-03-14
问题内容

我有一个问题要设计一个好的算法,该算法使用此处描述的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作为查询参数的字符串一起使用。

我尚未对此进行测试,但是它应该为您提供正确的想法并帮助您解释问题所在。

*像这样进行字符串插值时要 *格外小心
,这是SQL注入的简便方法。我已经在上面显示的代码中做了非常粗略的引用,但是如果您的客户端库提供了一个标识符引用功能,我想使用一个适当的标识符引用功能。



 类似资料:
  • 问题内容: 我正在使用PDO,并希望执行以下操作: PDO是否允许我这样绑定表名和列名?这 似乎是 允许的,但是却让我周围的报价参数,即使我用PDO :: PARAM_INT或PDO :: PARAM_BOOL作为数据类型。 如果这不起作用,如何安全地对变量进行转义,以便可以在查询中对它们进行插值? 问题答案: 不幸的是,您不能按列名绑定参数。 您可以尝试动态创建SQL命令: 只要确保对参数/变量

  • 痛点 在Java开发中我们要面对各种各样的类型转换问题,尤其是从命令行获取的用户参数、从HttpRequest获取的Parameter等等,这些参数类型多种多样,我们怎么去转换他们呢?常用的办法是先整成String,然后调用XXX.parseXXX方法,还要承受转换失败的风险,不得不加一层try catch,这个小小的过程混迹在业务代码中会显得非常难看和臃肿。 Convert类 Convert类可

  • }} 这是android设备监视器的崩溃报告

  • 问题内容: 我曾尝试使用FLINQ,但F#3.0 beta版已经过时了。 有人可以给我一些关于如何在F#中创建动态SQL查询的指示吗? 问题答案: 在F#3.0中,查询会自动加引号,因此您不能使用引号拼接(语法)来构成查询。通过使用拼接来组成查询,您可以编写的大多数内容仍可以通过“常规LINQ方式”来完成,方法是从先前的源创建一个新查询并添加即过滤: 这样,您可以动态添加条件,动态指定投影(使用)

  • 本文向大家介绍Python静态类型检查新工具之pyright 使用指南,包括了Python静态类型检查新工具之pyright 使用指南的使用技巧和注意事项,需要的朋友参考一下 Python是一门动态类型的语言,民间流传一种说法叫”动态一时爽,重构火葬场”,听起来够吓人的,好在这门语言在不断地改进,包括对 PEP484 引入的类型提示(Type Hint),就是在某种程度上,让Python能够像静态

  • 我是JavaFx新手,尝试用三个StackPane构建下面的屏幕,可以根据窗口大小动态地增加和缩小宽度和高度。我尝试了不同的方法,但没能做到这一点。我还尝试使用锚烷约束。这是我试图实现的图像和相应的FXML。以下是我在这些窗格之间寻找的约束条件 左窗格具有最大宽度(300px)和最小150 左右之间的距离(2)堆栈窗格应保持不变 右顶部和底部堆栈窗格之间的距离应保持不变 左顶部堆栈窗格的最大高度为