【问题标题】:Copying CSV to PostgreSQL database using Psycopg3 in Python在 Python 中使用 Psycopg3 将 CSV 复制到 PostgreSQL 数据库
【发布时间】:2021-11-05 23:30:24
【问题描述】:

我在理解 Python 中 psycopg3 库的适当语法时有点困难。我正在尝试将 .csv 文件的内容复制到我的数据库中。 The PostgreSQL documentation 表示copy 应该这样写:

COPY table_name [ ( column_name [, ...] ) ]
    FROM { 'filename' | PROGRAM 'command' | STDIN }
    [ [ WITH ] ( option [, ...] ) ]
    [ WHERE condition ]

所以我写了我的python语句如下:

import psycopg


with psycopg.connect('dbname=ideatest user=postgres password=password') as conn: 
        with conn.cursor() as cur:
            mock_idea_info = open(r'C:\dir\filename.csv')
            cur.copy('public.ideastorage FROM C:\dir\filename.csv;')

print('Copy successful.')

问题是脚本打印“复制成功”,但没有将数据插入数据库。不会生成错误消息。我在文件路径中复制了 \ 字符,所以这不是问题。我一直在寻找解决方案和可能的故障排除方法,但还没有找到任何我理解的似乎相关的东西。

另外,有什么方法可以将mock_idea_info 直接传递到copy 语句中?

任何帮助将不胜感激。

【问题讨论】:

  • 这能回答你的问题吗? Insert pandas data frame into Postgres
  • 好吧。我确信该解决方案有效。我试图避免使用另一个库来管理 SQL 语句。在那个解决方案中,似乎使用了 SQLAlchemy。我一直在寻找一种 psycopg 解决方案。我可以使用其他一些功能更简单的库,但感觉那是一种草率的编码。
  • 参见此处COPY,“逐块复制”示例。
  • 我在写问题时打开了那个确切的页面,但我并不完全理解它。我的python-fu没那么强。带有 open('data', 'r') 的语句似乎是根据文件名打开文件。我看到。而 while 循环似乎将值迭代地写入数据库,直到文档完成读取。但是这条线:with cursor.copy("COPY data FROM STDIN") as copy给我带来了麻烦。似乎整个文件正在被转换为一个对象,然后存储并(以某种方式)分解为数据库中基于列的存储。对吗?
  • 查看我的答案以获取示例。我还在弄清楚psycopg3,所以答案可能需要完善,但我认为这将作为一个开始。

标签: python database postgresql copy psycopg3


【解决方案1】:

Copy from:

cat data.out 
1       2
2       1

\d csv_test 
              Table "public.csv_test"
 Column |  Type   | Collation | Nullable | Default 
--------+---------+-----------+----------+---------
 col1   | integer |           |          | 
 col2   | integer |           |          | 


with open("data.out", "r") as f:
     with cur.copy("COPY csv_test FROM STDIN") as copy:
         while data := f.read(100):
            copy.write(data)
con.commit()

select * from csv_test ;
 col1 | col2 
------+------
    1 |    2
    2 |    1

--Add format options
cat data.out 
1,2
2,1
with open("data.out", "r") as f:
     with cur.copy("COPY csv_test FROM STDIN WITH (FORMAT CSV)" ) as copy:
         while data := f.read(100):
            copy.write(data)
con.commit()

select * from csv_test ;
 col1 | col2 
------+------
    1 |    2
    2 |    1
    1 |    2
    2 |    1

以上内容改编自链接中的示例。这个while data := f.read(100) 使用的海象(:=)仅在 Python 3.8+ 中可用

【讨论】:

    【解决方案2】:

    我没有看到您在输入后承诺将数据保留在数据库中。尝试添加这个:

    conn.commit()
    

    【讨论】:

    • 如果我没记错的话,当使用 with 关键字作为上下文时,conn.commit() 会在关闭时自动执行。不过我还是试了一下,不影响输出。
    【解决方案3】:

    您可能应该包含with (format csv) 子句(请参阅https://www.postgresql.org/docs/current/sql-copy.html)或明确指定引号和分隔符。

    【讨论】:

    • psycopg3 文档明确表示不要理会这些条款。它掠过我的脑海。我认为 psycopg3 有一种独特的做事方式。
    • 在逐块复制时,就像使用文件一样,psycopg3 文档说“在这种情况下,只要输入数据兼容,您就可以使用任何 COPY 选项和格式。”
    • 逐行写入/读取时,不能使用附加子句。正如在按块写入/读取时指出的那样,您可以使用它们。
    猜你喜欢
    • 2015-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多