gpt4 book ai didi

sql - 为什么带有 DELETE 的 PostgreSQL CTE 不起作用?

转载 作者:行者123 更新时间:2023-11-29 14:30:16 24 4
gpt4 key购买 nike

如果同一表中的更新导致使用两个 CTE 的数量为 0,我试图从我的库存表中删除一条记录。upserts 正在工作,但 delete 没有产生我期望的结果。库存表中的数量正在更改为零,但记录未被删除。表结构:

CREATE TABLE IF NOT EXISTS stock_location (
stock_location_id SERIAL
, site_code VARCHAR(10) NOT NULL
, location_code VARCHAR(50) NOT NULL
, status CHAR(1) NOT NULL DEFAULT 'A'
, CONSTRAINT pk_stock_location PRIMARY KEY (stock_location_id)
, CONSTRAINT ui_stock_location__keys UNIQUE (site_code, location_code)
);

CREATE TABLE IF NOT EXISTS stock (
stock_id SERIAL
, stock_location_id INT NOT NULL
, item_code VARCHAR(50) NOT NULL
, quantity FLOAT NOT NULL
, CONSTRAINT pk_stock PRIMARY KEY (stock_id)
, CONSTRAINT ui_stock__keys UNIQUE (stock_location_id, item_code)
, CONSTRAINT fk_stock__stock_location FOREIGN KEY (stock_location_id)
REFERENCES stock_location (stock_location_id)
ON DELETE CASCADE ON UPDATE CASCADE
);

语句是这样的:

WITH stock_location_upsert AS (
INSERT INTO stock_location (
site_code
, location_code
, status
) VALUES (
inSiteCode
, inLocationCode
, inStatus
)
ON CONFLICT ON CONSTRAINT ui_stock_location__keys
DO UPDATE SET
status = inStatus
RETURNING stock_location_id
)
, stock_upsert AS (
INSERT INTO stock (
stock_location_id
, item_code
, quantity
)
SELECT
slo.stock_location_id
, inItemCode
, inQuantity
FROM stock_location_upsert slo
ON CONFLICT ON CONSTRAINT ui_stock__keys
DO UPDATE SET
quantity = stock.quantity + inQuantity
RETURNING stock_id, quantity
)
DELETE FROM stock stk
USING stock_upsert stk2
WHERE stk.stock_id = stk2.stock_id
AND stk.quantity = 0;

有人知道这是怎么回事吗?

这是我正在尝试做的一个例子:

DROP TABLE IF EXISTS test1;

CREATE TABLE IF NOT EXISTS test1 (
id serial
, code VARCHAR(10) NOT NULL
, description VARCHAR(100) NOT NULL
, quantity INT NOT NULL
, CONSTRAINT pk_test1 PRIMARY KEY (id)
, CONSTRAINT ui_test1 UNIQUE (code)
);

-- UPSERT
WITH test1_upsert AS (
INSERT INTO test1 (
code, description, quantity
) VALUES (
'01', 'DESC 01', 1
)
ON CONFLICT ON CONSTRAINT ui_test1
DO UPDATE SET
description = 'DESC 02'
, quantity = 0
RETURNING test1.id, test1.quantity
)
DELETE FROM test1
USING test1_upsert
WHERE test1.id = test1_upsert.id
AND test1_upsert.quantity = 0;

UPSERT 命令第二次运行时,一旦数量更新为零,它应该从 test1 中删除记录。

有道理吗?

最佳答案

在这里,DELETE 以其设计的方式工作。答案实际上非常简单并且有据可查。几年前我也经历过同样的行为。

您的 delete 并没有真正删除数据的原因是,就 delete 语句而言,您的 where 条件与存储在表中的内容不匹配。

CTE(公用表表达式)中的所有子语句都使用数据的相同快照执行,因此它们看不到其他语句效果 在目标表上。在这种情况下,当您运行 UPDATE 然后运行 ​​DELETE 时,DELETE 语句看到的数据与 UPDATE 看到的相同,并且看不到 UPDATE 语句修改的更新数据。

您如何解决这个问题?您需要将 UPDATE 和 DELETE 分成两个独立的语句。

如果您需要传递有关要删除的内容的信息,例如您可以(1) 创建一个临时表并插入已更新的数据主键,以便您可以加入该表在您的后一个查询中(根据已更新的数据进行删除)。 (2) 您可以通过简单地在更新的表格中添加一列并更改其值以标记更新的行或 (3) 来获得相同的结果完成的工作。通过上面的例子,你应该能感觉到需要做什么。

引用手册来支持我的发现:<强> 7.8.2. Data-Modifying Statements in WITH

The sub-statements in WITH are executed concurrently with each other and with the main query. Therefore, when using data-modifying statements in WITH, the order in which the specified updates actually happen is unpredictable. All the statements are executed with the same snapshot (see Chapter 13), so they cannot “see” one another's effects on the target tables.

(...) This also applies to deleting a row that was already updated in the same statement: only the update is performed

关于sql - 为什么带有 DELETE 的 PostgreSQL CTE 不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52919715/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com