我正在编写一个访问我的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
中提取序列值。
答案 0 :(得分:0)
基本上(但请继续阅读!),您希望先INSERT
行foo
,然后使用自动生成的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}}