PostgreSQL从主键获取串口值到外键

时间:2014-12-07 02:21:14

标签: python sql database postgresql concurrency

我正在编写一个访问我的postgres数据库的python脚本。另外,我正在导入一个.csv文件来获取数据并将其传输到postgres数据库。

我有这样的事情,如果我似乎无法正确格式化,我会道歉,因为我是新来的。

表foo:

A SERIAL NOT NULL PRIMARY KEY
B
C

表栏:

D INT NOT NULL PRIMARY KEY
E
F INT REFERENCES foo(A) 

我的代码看起来像这样:

csvfile = open('something.csv')
conn = psycopg2.connect("dbname=something user=something password=something")
cur = conn.cursor()
datareader = csv.DictReader(csvfile, delimiter=',')

for row in datareader:

cur.execute("INSERT INTO bar (D, E, F) VALUES (%s, %s, %s)", (row['some_int'], row['some_char']), [not_sure_what_goes_here])

我不知道如何从表foo中提取序列值。

1 个答案:

答案 0 :(得分:0)

基本解决方案

基本上(但请继续阅读!),您希望先INSERTfoo,然后使用自动生成的A作为下一个INSERT 1}}进入bar
可以通过两次往返数据库来实现这一点,但这将是不合理的昂贵的,并且更容易受到并发问题的影响。您希望在single trip to the DB中完成此操作。

在Postgres 9.1+中,您可以使用数据修改CTE 在一个语句中执行两个插入:

cur.execute("""WITH ins AS (
   INSERT INTO foo (B, C)
   VALUES (%s, %s)
   RETURNING A
   )
INSERT INTO bar (D, E, F)
SELECT %s, %s, A
FROM ins""", (val_for_b, val_for_c, val_for_d, val_for_e)

,上述代码表示您可以无条件地将(B, C)插入foo。这种情况很少发生。通常,您在foo上有某种独特约束,并且只有在(B, C)不存在时才想插入cur.execute("""WITH param(_B, _C) AS (SELECT %s::text, %s::text) , sel AS (SELECT A FROM foo, param WHERE B = _B AND C = _C FOR SHARE) , ins AS ( INSERT INTO foo (B, C) SELECT _B, _C FROM param WHERE NOT EXISTS (SELECT 1 FROM sel) RETURNING A ) INSERT INTO bar (D, E, F) SELECT %s, %s, COALESCE(sel.A, ins.A) FROM sel FULL JOIN ins""", (val_for_b, val_for_c, val_for_d, val_for_e) 。你有一个" SELECT-or-INSERT "问题,由于可能的竞争条件进一步使用并发写操作(如果可能)。最佳解决方案取决于您的确切要求。

最安全的解决方案

解决" SELECT-or-INSERT"问题以及最小化竞争条件的可能性:

::text

将类型转换foo替换为您的实际数据类型(您未提供) 对于大多数用例来说,这应该足够好了。当两个事务试图同时在cur.execute("""INSERT INTO bar (D, E, F) VALUES(%s, %s, f_foo_id(%s, %s))""", (val_for_d, val_for_e, val_for_b, val_for_c) 中插入同一行时,它仍会为竞争条件留下很小的机会。

安全解决方案

要完全确定,请考虑此相关答案中讨论的服务器端功能。您还可以找到上述SQL代码的详细说明:

然后你的电话可以是:

{{1}}