解析 CSV 文件,循环并将行插入 PostGreSQL 数据库
Parse a CSV file, loop and insert rows into a PostGreSQL database
我使用 Python psycopg2 模块将 csv 文件(用户列表)的内容复制到 PostGreSQL 数据库中。
所以我开始用 Python pandas 模块解析 CSV。然后使用 for 循环,我尝试将我的数据插入到我的 SQL 查询中。
我有两个问题:
a) 当我执行角色查询(查询 2 - 见下文)以在数据库中创建新角色时,我得到 'user' 而不是 用户 。我该怎么做才能使用正确的语法插入角色?
b) 查询 3 和 4(见下文) 给出以下错误:
TypeError: not all arguments converted during string formatting
这个问题究竟是什么以及如何解决?
完整代码如下:
import csv, psycopg2
import pandas as pd
conn = psycopg2.connect("host=localhost dbname=vmap user=postgres password=postgres port=5432")
c = conn.cursor()
# Import_CSV
data = pd.read_csv (r'users.csv', sep=';')
df = pd.DataFrame(data, columns= ['id','login','mdp','mail','date'])
print(df)
for row in df.itertuples():
print (row.login)
c.execute("INSERT INTO users (user_id, login, email) VALUES(%s, %s, %s);", (row.id, row.login, row.mail))
# query2
c.execute('create role "%s" with encrypted password %s',(row.login, row.mdp))
# query3
c.execute('grant vitis_user, vmap_user to "%s"',(row.login))
# query4
c.execute('grant connect on vmap to "%s"',(row.login))
我要解析的 DataFrame(CSV 文件的内容)是这个:
id login ... mail date
0 10 ldeschamps-diallo ... ldeschamps-diallo@monwebsig.com 2022-01-31
1 11 pmarion ... pmarion@monwebsig.com 2022-01-31
2 12 cleroy ... cleroy@monwebsig.com 2022-01-31
3 13 lcourtois ... lcourtois@monwebsig.com 2022-01-31
4 14 rpaul-monnier ... rpaul-monnier@monwebsig.com 2022-01-31
正在读取 CSV
首先,这里可能不需要pandas
,因为你只需要打开csv文件并解析它的内容。使用 built-in csv
模块应该足够了。
您可以这样阅读文件:
import csv
with open("users.csv", "r", encoding="utf-8", newline="") as fid:
reader = csv.reader(fid, delimiter=";")
正在加载
正如 Adrian Klaver 所建议的,您可以使用 .copy_from
方法加载数据,但这只会帮助您解决问题的第一部分,即插入用户。您将从查询编号 2 开始处理您现在面临的相同问题。
说明
另一件事是,psycopg2
为您提供参数化查询以保护您免受 SQL injection 的影响,但设计为在您尝试使用它时转义 'values' 时工作'identifier'。当您第一次将用户插入 table 时,用户名是一个要插入的值,一切都按预期进行。在第二个查询中,您指的是数据库中的实际用户(请注意,您使用 "
而不是 '
来转义用户名)。因为 psycopg2
用户名是一个值,它用额外的 '
转义它,你最终得到这样的查询:
create role "'cleroy'" with encrypted password 'password'
如果您想传递用户名,您可能需要使用字符串格式:
c.execute(f'create role "{row.login}" with encrypted password %s',(row.mdp,))
但这样一来,您就可以接受 sql 注入。想象一下有一个用户名 tom"; DROP DATABASE mysuperdatabase;
。这样,您将得到查询:
create role "tom"; DROP DATABASE mysuperdatabase;
并且您面临丢失宝贵数据的潜在风险。
安全的方法
所以你首先需要做的是确保标识符被正确转义。您可以使用 psycopg2.sql
模块来执行此操作。
from psycopg2 import sql
login = sql.Identifier(row.login)
query = sql.SQL(f"create role {login} with encrypted password %s")
c.execute(query, (row.mdp,))
我使用 Python psycopg2 模块将 csv 文件(用户列表)的内容复制到 PostGreSQL 数据库中。
所以我开始用 Python pandas 模块解析 CSV。然后使用 for 循环,我尝试将我的数据插入到我的 SQL 查询中。
我有两个问题:
a) 当我执行角色查询(查询 2 - 见下文)以在数据库中创建新角色时,我得到 'user' 而不是 用户 。我该怎么做才能使用正确的语法插入角色?
b) 查询 3 和 4(见下文) 给出以下错误:
TypeError: not all arguments converted during string formatting
这个问题究竟是什么以及如何解决?
完整代码如下:
import csv, psycopg2
import pandas as pd
conn = psycopg2.connect("host=localhost dbname=vmap user=postgres password=postgres port=5432")
c = conn.cursor()
# Import_CSV
data = pd.read_csv (r'users.csv', sep=';')
df = pd.DataFrame(data, columns= ['id','login','mdp','mail','date'])
print(df)
for row in df.itertuples():
print (row.login)
c.execute("INSERT INTO users (user_id, login, email) VALUES(%s, %s, %s);", (row.id, row.login, row.mail))
# query2
c.execute('create role "%s" with encrypted password %s',(row.login, row.mdp))
# query3
c.execute('grant vitis_user, vmap_user to "%s"',(row.login))
# query4
c.execute('grant connect on vmap to "%s"',(row.login))
我要解析的 DataFrame(CSV 文件的内容)是这个:
id login ... mail date
0 10 ldeschamps-diallo ... ldeschamps-diallo@monwebsig.com 2022-01-31
1 11 pmarion ... pmarion@monwebsig.com 2022-01-31
2 12 cleroy ... cleroy@monwebsig.com 2022-01-31
3 13 lcourtois ... lcourtois@monwebsig.com 2022-01-31
4 14 rpaul-monnier ... rpaul-monnier@monwebsig.com 2022-01-31
正在读取 CSV
首先,这里可能不需要pandas
,因为你只需要打开csv文件并解析它的内容。使用 built-in csv
模块应该足够了。
您可以这样阅读文件:
import csv
with open("users.csv", "r", encoding="utf-8", newline="") as fid:
reader = csv.reader(fid, delimiter=";")
正在加载
正如 Adrian Klaver 所建议的,您可以使用 .copy_from
方法加载数据,但这只会帮助您解决问题的第一部分,即插入用户。您将从查询编号 2 开始处理您现在面临的相同问题。
说明
另一件事是,psycopg2
为您提供参数化查询以保护您免受 SQL injection 的影响,但设计为在您尝试使用它时转义 'values' 时工作'identifier'。当您第一次将用户插入 table 时,用户名是一个要插入的值,一切都按预期进行。在第二个查询中,您指的是数据库中的实际用户(请注意,您使用 "
而不是 '
来转义用户名)。因为 psycopg2
用户名是一个值,它用额外的 '
转义它,你最终得到这样的查询:
create role "'cleroy'" with encrypted password 'password'
如果您想传递用户名,您可能需要使用字符串格式:
c.execute(f'create role "{row.login}" with encrypted password %s',(row.mdp,))
但这样一来,您就可以接受 sql 注入。想象一下有一个用户名 tom"; DROP DATABASE mysuperdatabase;
。这样,您将得到查询:
create role "tom"; DROP DATABASE mysuperdatabase;
并且您面临丢失宝贵数据的潜在风险。
安全的方法
所以你首先需要做的是确保标识符被正确转义。您可以使用 psycopg2.sql
模块来执行此操作。
from psycopg2 import sql
login = sql.Identifier(row.login)
query = sql.SQL(f"create role {login} with encrypted password %s")
c.execute(query, (row.mdp,))