【问题标题】:How to get psycopg2's description from PostgreSQL server side cursor如何从 PostgreSQL 服务器端游标获取 psycopg2 的描述
【发布时间】:2020-06-19 19:38:28
【问题描述】:

我构建了一个获取任意 Postgres SQL 查询、获取数据并创建 CSV 文件的类。我正在使用 cursor.description 获取列名,并将其作为我的 csv 标题传递。但是数据集太大了,我正在转向服务器端游标。

服务器端游标似乎没有任何描述数据。当我跑步时:

import psycopg2

conn = psycopg2.connect(**conn_info)
cursor = conn.cursor("server_side")
cursor.execute("select * from foo")
print(cursor.description)

它打印None,可能是因为查询实际上并没有运行。但是有没有办法在这个配置中获取列名?

【问题讨论】:

    标签: python-3.x postgresql


    【解决方案1】:

    cursor.execute('select...') 中的查询在服务器端执行,但应用程序还没有数据,因此 cursor.description 未定义。要获取描述,您需要从服务器端游标中至少获取一行,例如:

    cursor = conn.cursor("server_side")
    # or
    # cursor = conn.cursor("server_side", scrollable=True)
    # see below
    cursor.execute("select * from my_table")
    first_row = cursor.fetchone()
    print(cursor.description)
    # you can place the cursor in the initial position if needed:
    # cursor.scroll(-1) 
    

    请注意,当表格为空时,您不会得到描述。

    没有更好(更快或更简单)的方法来获取命名游标的查询结果描述。这是由于命名游标的实现方式。命令

    cursor = conn.cursor("server_side")
    cursor.execute("select * from my_table")
    

    通过使用 Postgres 命令声明游标来实现:

    DECLARE "server_side" CURSOR WITHOUT HOLD FOR select * from my_table
    

    the documentation:

    DECLARE 允许用户创建游标,可用于从较大的查询中一次检索少量行。创建游标后,使用 FETCH 从中获取行。

    游标声明本身不提供有关结果结构的任何信息。只有通过FETCH命令获取一行或多行后才能获取。

    【讨论】:

    • 这个答案和this one 都很有用,最好一起使用。我把我的赏金给了@Lucan,因为,比方说,他们对奖励的需求比你的更大。希望你没事。
    【解决方案2】:

    这里的其他答案是;不幸的是,答案和原因如下。如果不首先调用fetch,就无法从服务器端游标中获取description 甚至rowcount。它根据PEP-249返回None

    对于不返回行的操作或游标尚未通过.execute*() 方法调用的操作,此属性将为None

    这是因为即使您调用了execute,服务器可能还没有执行查询,我们可以通过检查日志来确认(其中日志记录设置为all

    为了清楚起见,使用以下代码和 30 秒的睡眠

    cursor = conn.cursor("server_side")
    cursor.execute("select * from foo")
    time.sleep(30)
    cursor.fetchall()
    print(cursor.description)
    

    日志将显示

    2020-06-19 12:11:37.687 BST [11916] LOG:  statement: BEGIN
    2020-06-19 12:11:37.687 BST [11916] LOG:  statement: DECLARE "server_side" CURSOR WITHOUT HOLD FOR select * from foo
    2020-06-19 12:12:07.693 BST [11916] LOG:  statement: FETCH FORWARD ALL FROM "server_side"
    

    注意声明和FETCH之间的30~秒间隔,后者是允许我们从光标中获取description的调用。

    没有server_side比较

    2020-06-19 12:11:01.310 BST [3012] LOG:  statement: BEGIN
    2020-06-19 12:11:01.311 BST [3012] LOG:  statement: select * from foo
    

    您唯一的选择是在更大的查询之前使用scroll 或执行LIMIT 1 选择。

    一个不太吸引人的选择是像这样使用INFORMATION_SCHEMA

    select column_name, data_type, character_maximum_length
    from INFORMATION_SCHEMA.COLUMNS where table_name = 'foo';
    

    【讨论】:

      【解决方案3】:

      你不能这样做吗:

      import psycopg2
      
      conn = psycopg2.connect(**conn_info)
      cursor_desc = conn.cursor()
      cursor_desc.execute("select * from foo limit 1")
      print(cursor_desc.description)
      cursor = conn.cursor("server_side")
      cursor.execute("select * from foo")
      

      那么你就没有搞乱服务器端数据返回查询。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-05-17
        • 2020-02-24
        • 2015-08-11
        • 1970-01-01
        • 1970-01-01
        • 2020-11-13
        • 2022-08-19
        • 2012-05-02
        相关资源
        最近更新 更多