在Python中使用psycopg2以OrderedDict的形式返回PostgreSQL hstore

在Python中使用psycopg2以OrderedDict的形式返回PostgreSQL hstore,python,postgresql,psycopg2,hstore,Python,Postgresql,Psycopg2,Hstore,PostgreSQL hstore维护存储和检索之间的顺序。这允许用户定义存储和检索hstore中的键/值的顺序 不幸的是,psycopg2的实现使用了extras.py->HstoreAdapter.parse()下的硬编码dict 虽然在大多数场景中,将hstore解析为dict套件都很好,但在我们的场景中,这会导致问题;我们特别需要维持订单 我得出的一个解决方法是将键和值作为单独的列表进行查询: 从mytbl中选择AKEYS(myhstore)作为键,选择AVALS(mytoore)作为V

PostgreSQL hstore维护存储和检索之间的顺序。这允许用户定义存储和检索hstore中的键/值的顺序

不幸的是,psycopg2的实现使用了
extras.py->HstoreAdapter.parse()下的硬编码dict

虽然在大多数场景中,将hstore解析为dict套件都很好,但在我们的场景中,这会导致问题;我们特别需要维持订单

我得出的一个解决方法是将键和值作为单独的列表进行查询:

从mytbl中选择AKEYS(myhstore)作为键,选择AVALS(mytoore)作为VAL

。。。但是,该解决方案处理的是问题的症状,而不是原因

有人知道这个问题的猴子补丁解决方案,或者处理这个问题的psycopg2分支,或者解决这个问题的extras.py文件的实现吗


或者,有人对如何处理这个问题有其他建议吗?

您可以转储到字符串并存储为文本

然后,您可以在json解码器中指定
object\u pairs\u hook

注意:不保留秩序。它与Python的
dict
一样无序。我先前的回答只是偶然的

成对的顺序不重要(输出时可能不会再现)

例如:

SELECT 'foo=>1,bar=>2,spam=>3,eggs=>4'::hstore
UNION ALL
SELECT hstore('{foo,1,bar,2,spam,3,eggs,4}'::TEXT[])
UNION ALL
SELECT hstore('{{foo,1},{bar,2},{spam,3},{eggs,4}}'::TEXT[])
UNION ALL
SELECT hstore('{foo,bar,spam,eggs}'::TEXT[], '{1,2,3,4}'::TEXT[])
所有结果如下:

""bar"=>"2", "foo"=>"1", "eggs"=>"4", "spam"=>"3""
""bar"=>"2", "foo"=>"1", "eggs"=>"4", "spam"=>"3""
""bar"=>"2", "foo"=>"1", "eggs"=>"4", "spam"=>"3""
""bar"=>"2", "foo"=>"1", "eggs"=>"4", "spam"=>"3""
它看起来是无序的,因为它的顺序与原始顺序不同,而且它不是按字母顺序排列的


下面的方法实际上不起作用

您可以使用将
HSTORE
转换为键值对数组的函数来维护
HSTORE
中的顺序。然后,您必须手动将其传递到Python中的
OrderedDict

import collections
import psycopg2
import psycopg2.extras

pg = psycopg2.connect(...)
psycopg2.extras.register_hstore(pg)
cursor = pg.cursor()

cursor.execute("""
    SELECT hstore_to_matrix('a=>1,b=>2,c=>3'::hstore);
""")
pairs = cursor.fetchone()[0]
ordered = collections.OrderedDict(pairs)

print(pairs)
# [['a', '1'], ['b', '2'], ['c', '3']]
print(ordered)
# OrderedDict([('a', '1'), ('b', '2'), ('c', '3')])
psycopg2
最终在将字典转换回
HSTORE
时调用字典上的
.keys()
.values()
,这意味着只要对字典进行排序,发送回PostgreSQL的
HSTORE
也将被排序。您只需传回一个
OrderedDict
,而不是常规的
dict
,即可维持秩序:

# This will save the data as ordered.
data = OrderedDict([('a', '1'), ('b', '2'), ('c', '3')])
cursor.update("""
    UPDATE mytable
    SET ordered = %(data)s;
""", {
    'data': data
})

# This will save the data as unordered. Whatever the internal order
# happens to be for the dict will be sent. When I run it in the python
# interpreter, it results in:
#   [('a', '1'), ('c', '3'), ('b', '2')]
cursor.update("""
    UPDATE mytable
    SET ordered = %(data)s;
""", {
    'data': data
})

您建议以纯文本形式存储,整体放弃hstore数据类型?如果系统的其他部分已经使用了hstore特定的功能,例如键或值的索引,将键/值对作为单独的行返回(使用
each()
),或者使用任何其他hstore特定的功能,该怎么办?这个答案假设hstore仅用作存储机制,并且没有使用一个hstore功能;一个非常广泛和危险的假设,“可能”很难成为一个建议。您知道自己的限制,并且在提供所有选项时可以采取最佳方法。
# This will save the data as ordered.
data = OrderedDict([('a', '1'), ('b', '2'), ('c', '3')])
cursor.update("""
    UPDATE mytable
    SET ordered = %(data)s;
""", {
    'data': data
})

# This will save the data as unordered. Whatever the internal order
# happens to be for the dict will be sent. When I run it in the python
# interpreter, it results in:
#   [('a', '1'), ('c', '3'), ('b', '2')]
cursor.update("""
    UPDATE mytable
    SET ordered = %(data)s;
""", {
    'data': data
})