Вернуть массив PostgreSQL UUID в виде списка с помощью psycopg2

У меня есть оператор SQL, который содержит подзапрос, встроенный в ARRAY(), например:

SELECT foo, ARRAY(SELECT x from y) AS bar ...

Запрос работает нормально, однако в курсоре результатов psycopg2 массив возвращается в виде строки (как в "{1,2,3}"), а не списка.

Мой вопрос: как лучше всего преобразовать такие строки в списки Python?


person Ben Scott    schedule 28.05.2013    source источник


Ответы (3)


У меня работает без разбора:

import psycopg2

query = """
    select array(select * from (values (1), (2)) s);
"""

conn = psycopg2.connect('dbname=cpn user=cpn')
cursor = conn.cursor()
cursor.execute(query)
rs = cursor.fetchall()

for l in rs:
    print l[0]

cursor.close()
conn.close()

Результат при выполнении:

$ python stackoverflow_select_array.py 
[1, 2]

Обновлять

Вам необходимо зарегистрировать тип uuid:

import psycopg2, psycopg2.extras

query = """
    select array(
        select *
        from (values
            ('A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11'::uuid),
            ('A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11'::uuid)
        )s
    );
"""

psycopg2.extras.register_uuid()

conn = psycopg2.connect('dbname=cpn user=cpn')
cursor = conn.cursor()
cursor.execute(query)
rs = cursor.fetchall()

for l in rs:
    print l[0]

cursor.close()
conn.close()

Результат:

$ python stackoverflow_select_array.py 
[UUID('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'), UUID('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11')]
person Clodoaldo Neto    schedule 28.05.2013
comment
Большое спасибо за это, я вернулся и еще немного поиграл с кодом, и вы правы, он работает, но только для типов столбцов Integer и String. Столбец, который я получаю в массиве, на самом деле имеет тип UUID, и он все еще возвращается в виде строки. Извините, я слишком упростил свой код, когда я первоначально опубликовал, я не понимал, что тип столбца повлияет на это. - person Ben Scott; 28.05.2013

Если каждый результирующий курсор ARRAY имеет формат '{x,y,z}', то вы можете сделать это, чтобы удалить строку фигурных скобок и разделить ее на список с разделителем-запятой:

>>> s = '{1,2,3}'
>>> s
'{1,2,3}'
>>> l = s.rstrip('}').lstrip('{').split(',')
>>> l
['1', '2', '3']
>>>
>>> s = '{1,2,3,a,b,c}'
>>> s
'{1,2,3,a,b,c}'
>>> l = s.rstrip('}').lstrip('{').split(',')
>>> l
['1', '2', '3', 'a', 'b', 'c']
person Gurkaran Singh    schedule 28.05.2013
comment
Спасибо за это, это работает. Если я не могу понять, почему ARRAY() не работает для полей UUID (см. ниже), я выберу этот подход. - person Ben Scott; 28.05.2013

Другой способ справиться с этим - явно указать postgres, что вам нужен текст, тогда сработает логика разбора строки psycopg2 по умолчанию, и вы получите список:

db = psycopg2.connect('...')
curs = db.cursor()
curs.execute("""
    SELECT s.id, array_agg(s.kind::text)
        FROM (VALUES ('A', 'A0EEBC99-9C0B-AEF8-BB6D-6BB9BD380A11'::uuid),
                     ('A', 'A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A12'::uuid)) AS s (id, kind)
    GROUP BY s.id
""")
for row in curs:
    print "row: {}".format(row)

Результат:

row: (u'A', [u'a0eebc99-9c0b-aef8-bb6d-6bb9bd380a11', u'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a12'])

и запрос

curs.execute("""
    SELECT array(
        SELECT s.kind::text
        FROM (VALUES ('A0EEBC99-9C0B-AEF8-BB6D-6BB9BD380A11'::uuid),
                     ('A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A12'::uuid)) AS s (kind))
""")
for row in curs:
    print "row: {}".format(row)

приводит к:

row: ([u'a0eebc99-9c0b-aef8-bb6d-6bb9bd380a11', u'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a12'],)

Хитрость заключается в том, чтобы специально прикрепить ::text к интересующим вас полям.

person quodlibetor    schedule 21.09.2016