【问题标题】:How does this SQL query to update a row if exists, or insert if not, work?如果存在则更新行或不存在则插入的 SQL 查询如何工作?
【发布时间】:2025-12-10 23:40:01
【问题描述】:

我正在处理一些代码。有几个查询的效果是,如果行存在并填充了一些数据,则用其余数据更新该行,如果该行不存在,则创建一个新行。它们看起来像这样:

插入表名(col1,col2,col3) 选择 %s 作为 COL1、%s 作为 COL2、%s 作为 COL3 从(选择 %s 作为 COL1,%s 作为 COL2,%s 作为 COL3)A 左连接表名 B 开 B.COL1 = %s AND B.COL2 = %s --注意:这里没有提到所有列 B.id 为空 限制 1

我可以模仿这种模式并且它似乎有效,但我对幕后实际发生的事情感到困惑。谁能阐明这实际上是如何工作的?我正在使用 PostgreSQL。

【问题讨论】:

    标签: sql postgresql insert-update


    【解决方案1】:

    您确定只使用那段代码进行更新吗?

    正在发生的事情是,您正在使用 table_name(插入新记录的表)进行左连接,并仅过滤该表中不存在的行。 (其中 B.id 为 NULL)

    就像做“不存在”,只是方式不同。

    希望我的回答能帮到你。

    问候。

    【讨论】:

    • 啊,所以这实际上不会更新已经存在的条目?它只是确保不会创建重复的行?
    • 是的,where 子句只是为了确保没有重复。
    • 这样做与类似:INSERT INTO table_name (col1, col2, col3) SELECT %s, %s, %s WHERE NOT EXISTS (SELECT * FROM table_name as T WHERE T.col1 = %s AND T.col2 = %s)?
    • 我相信左连接比 where 子句中不存在的性能更好。但我不确定。我必须测试一下:-)。
    【解决方案2】:

    LEFT JOIN/IS NULL 表示查询正在插入不存在的记录。这是假设在 INSERT 子句中定义的表与 LEFT JOIN 子句中的表相同 - 小心抽象...

    我很想知道%s 是什么

    【讨论】:

    • 我怀疑这是类似 'sprintf()' 的函数的格式字符串,在 SQL 发送到 DBMS 之前,'%s' 将被替换为某种名称或值.
    • 是的,%s 是要放入表中的数据(您可以假设它是“foo”、“bar”、“baz”)。