1

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

我目前正在尝试在测试表中进行简单的替换测试,然后再转到具有更多数据的开发表。

我想用表 users 中已经存在的名称替换 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))
4

2 回答 2

2

您需要在 name 的值周围加上单引号:SET name='TEST' 双引号用于表名或列名。在您的情况下,您可以删除users.

编辑后:你真的应该在数据库控制台中尝试你的 SQL 命令,这与 python 或异步无关。它是纯 postgresql 语法。

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

然后,你会得到column reference "name" is ambiguous. 你应该写DO UPDATE SET name='TEST'。您已经在更新 row where name=excluded.name。我不是 100% 清楚你想要做什么。因此,如果您插入一行一次,它会像往常一样插入。如果您再次插入它,则名称将替换为“TEST”。exclude 关键字允许您访问尝试的插入值。因此,例如,如果您想last_access在尝试插入现有名称时更新列,您可以编写ON CONFLICT (name) DO UPDATE last_access=excluded.last_access.

于 2018-11-09T17:05:57.270 回答
1

你可以测试替换:'''INSERT INTO users(name, dob) VALUES($1, $2) ON CONFLICT (name) DO UPDATE "users" SET name = 'TEST' WHERE name = exclude.name '''

通过:“”“插入用户(姓名,出生日期)值($ 1,$ 2)冲突(姓名)DO UPDATE SET name ='TEST' WHERE name = exclude.name“”“

于 2018-11-23T22:51:43.657 回答