UPSERT语法错误链接到PostgreSQL中的UPDATE(python)

时间:2018-11-09 16:36:25

标签: python-3.x postgresql psycopg2 asyncpg

我还在学习PostgreSQL。在测试期间,我仅在psycopg2和现在的asyncpg中使用了INSERT语句。现在,我需要更新测试数据库中的数据,而不是全部替换。

我目前正在尝试在测试表中进行简单的替换测试,然后再移至包含更多数据的开发表。

我想用表用户中已经存在的名称替换CONFLICT中的任何$ 1名称。我正在尝试通过asyncpg传递到数据库的查询代码。我不断收到语法错误,因此我对如何更正这些错误有些困惑。

此查询的正确语法是什么?

'''INSERT INTO users(name, dob) 
   VALUES($1, $2)
   ON CONFLICT (name)
   DO 
     UPDATE "users"
     SET name = 'TEST'
     WHERE name = excluded.name '''

更新:

使用asyncpg时出现此错误消息:

asyncpg.exceptions.PostgresSyntaxError: syntax error at or near ""users""

使用psycopg2时出现此错误消息:

psycopg2.ProgrammingError: syntax error at or near ""users""

这是我用来执行INSERT的asyncpg代码:

async def insert_new_records(self, sql_command, data):

    print (sql_command)

    async with asyncpg.create_pool(**DB_CONN_INFO, command_timeout=60) as pool:
        async with pool.acquire() as conn:
            try:
                stmt = await conn.prepare(sql_command)
                async with conn.transaction():
                    for value in data:
                        async for item in stmt.cursor(*value):
                            pass
            finally:
                await pool.release(conn)


test_sql_command = '''
INSERT INTO users(name, dob)
VALUES($1, $2)
ON CONFLICT (name)
DO
  UPDATE "users"
  SET name = 'TEST'
  WHERE name = excluded.name '''

# The name 'HELLO WORLD' exists in the table, but the other name does not.
params = [('HELLO WORLD', datetime.date(1984, 3, 1)),
          ('WORLD HELLO', datetime.date(1984, 3, 1))]

loop = asyncio.get_event_loop()
loop.run_until_complete(db.insert_new_records(test_sql_command, params))

2 个答案:

答案 0 :(得分:2)

您需要在名称的值两边加上单引号:SET name='TEST' 双引号用于表或列的名称。就您而言,您只需删除users周围的双引号即可。

编辑后: 您实际上应该在数据库控制台中尝试SQL命令,这与python或async无关。这是纯postgresql语法。

因此,查询中的第二个问题是您不应该在UPDATE之后指定“用户”。暗示您正在更新同一张表。因此,DO UPDATE SET...很好。

然后,您将获得column reference "name" is ambiguous。您应该写DO UPDATE SET name='TEST'。您已经在更新where name=excluded.name行。我不确定您要做什么。因此,如果您插入一次行,则照常插入。如果第二次插入,则名称将替换为“ TEST”。 exclude关键字允许您访问尝试的插入值。因此,例如,如果要在尝试插入现有名称时更新last_access列,则可以编写ON CONFLICT (name) DO UPDATE last_access=excluded.last_access

答案 1 :(得分:0)

您可以测试 替换: '''INSERT INTO用户(名称,DOB)    VALUES($ 1,$ 2)    冲突时(姓名)    做      更新“用户”      SET名称=“测试”      WHERE名称= exclude.name'''

作者: “”“ INSERT INTO用户(名称,dob)    VALUES($ 1,$ 2)    冲突时(姓名)    做      更新      SET名称=“测试”      WHERE名称= exclude.name“”“