繁体   English   中英

PostgreSQL从主键到外键获取序列值

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM