使用SQL

时间:2019-12-02 12:34:15

标签: python postgresql csv

正在努力解决这个Python问题,因为我是新手,并且在该语言方面没有丰富的经验。我目前有一个CSV文件,其中包含大约20个标题和相同数量的行,因此像某些示例一样列出每个标题,这是我要避免的事情: https://www.dataquest.io/blog/loading-data-into-postgres/

到目前为止,我的代码包括以下内容:

  with open('dummy-data.csv', 'r') as f:
        reader = csv.reader(f)
        next(reader)
        for row in reader:
            cur.execute('INSERT INTO messages VALUES', (row))

在输入的末尾出现语法错误,因此我假设它与我的execute方法的编写方式有关,但是我仍然不知道该如何解决该问题。有帮助吗?

P.S。我了解该用户为此使用%s,但如果是这种情况,可以避免,因为我不想将其重复复制20次。

6 个答案:

答案 0 :(得分:1)

您可以使用字符串乘法。

import csv
import psycopg2

conn = psycopg2.connect('postgresql://db_user:db_user_password@server_name:port/db_name')
cur = conn.cursor()

multiple_placehorders = ','.join(['%s']*20)
with open('dummy-data.csv', 'r') as f:
    reader = csv.reader(f)
    next(reader)
    for row in reader:
        cur.execute('INSERT INTO public.messages VALUES (' + multiple_placehorders + ')', row)

conn.commit()

答案 1 :(得分:1)

问题出在插入物本身上:

 cur.execute('INSERT INTO messages VALUES', (row))

问题在于,由于您没有在查询中定义参数,因此它在解释您确实要执行INSERT INTO messages VALUES,而没有参数,这将导致语法错误;使用单个参数也不起作用,因为它将了解您需要单个参数,而不是多个参数。

如果要以更动态的方式创建参数,则可以尝试动态构造查询字符串。

请查看文档:{​​{3}}

答案 2 :(得分:1)

基本上,您必须在查询中至少指定所需的占位符-并且最好还指定字段名称。

如果是一次性事件,并且您知道CSV中的字段和顺序,则只需在查询中对它们进行硬编码,即

SQL =  "insert into tablename(field1, field2, field21) values(%s, %s, %s)"

好吧,对于20个左右的字段,它变得很无聊,因此您还可以使用字段名称列表来生成fieldnames部分和占位符:

fields = ["field1", "field2", "field21"]
placeholders = ["%s"] * len(fields) # list multiplication, yes

SQL = "insert into tablename({}) values({})".format(", ".join(fields), ", ".join(placeholders))

如果偶然情况下CSV标头行包含确切的字段名称,您也可以仅将此行用作fields的值-但此时您必须信任csv。

NB:并非严格要求在查询中指定字段列表,但可以保护您避免格式错误的CSV可能出现的问题。实际上,除非您真的信任源(您的csv),否则在将传入的数据发送到数据库之前,应该先对其进行积极验证。

NB2:

  

%s适用于我知道的字符串,但是它对时间戳是否起作用?

在这种情况下,"%s"不是用作Python字符串格式说明符,而是用作普通的数据库查询占位符。在这里选择字符串格式说明符确实很不幸,因为这会引起很多混乱。请注意,尽管这是特定于数据库供应商的,但某些供应商使用“?”相反,这更清晰,恕我直言(您想检查自己的db-api连接器的doc,以获取使用BTW的正确Plaeholder)。

由于它不是字符串格式说明符,因此它适用于任何类型,并且不需要为字符串加上引号,这是db-api模块的工作,根据db列的内容进行正确的格式化(包括引号等)类型。

尽管如此,但在将值传递给查询时绝对不要直接使用Python字符串格式化操作-unless you want your database to be open-bar for script-kiddies of course

答案 3 :(得分:1)

如果您希望使用一个占位符来覆盖整个值列表,则可以使用“ extras”中的另一种方法来覆盖该用法:

psycopg2.extras.execute_values(cur, 'INSERT INTO messages VALUES %s', (row,))

此方法一次可以占用很多行(这对性能有好处),这就是为什么您需要将单行包装在(...,)中。

答案 4 :(得分:0)

上次我努力将CSV数据插入到postgres中时,我使用了pgAdmin,并且它已经起作用了。我不知道这个答案是否是解决方案,但很容易与之相处。

答案 5 :(得分:-1)

您可以使用游标和executemany来跳过迭代,但是它比字符串连接参数化方法慢。

import pandas
df = pd.read_csv('dummy-data.csv')
df.columns = [<define the headers  here>] # You can skip this line if headers match column names
try:
    cursor.prepare("insert into public.messages(<Column Names>) values(:1, :2, :3 ,:4, :5)")
    cursor.executemany(None, df.values.tolist())
    conn.commit()
except:
    conn.rollback()