[英]PostgreSQL get serial value from primary key to foreign key
我正在编写访问我的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
提取序列值。
基本上,(但请继续阅读!),你要INSERT
一行到foo
第一和使用自动生成A
下一个INSERT
进入bar
。
您可以通过两次往返数据库的操作来做到这一点,但这将不合理地昂贵 ,并且更容易受到并发问题的影响。 您希望一次访问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)
。 您有一个“ SELECT-or-INSERT ”问题,并发写入操作(如果可能) 可能导致的竞争条件使问题更加复杂。 最佳解决方案取决于您的确切要求。
要解决“选择或插入”问题并最大程度地减少竞争情况的可能性,请执行以下操作:
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)
用您的实际数据类型(您未提供的类型)替换cast ::text
类型。
对于大多数用例,这应该足够好。 当两个事务试图同时在foo
插入同一行时,它仍然为竞争条件留下了很小的机会。
完全确定,请考虑此相关答案中讨论的服务器端功能。 您还将找到上述SQL代码的详细说明:
那么您的电话可以是:
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)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.