Sql 为什么这个子选择有效?不适用于本条款
我在编写PostgreSQL请求时犯了一个愚蠢的错误。语法似乎完全错误,但仍有一半的效果 我有这个表(订户): 还有其他行,但它们是唯一相关的行(具有相同的Sql 为什么这个子选择有效?不适用于本条款,sql,postgresql,sql-update,Sql,Postgresql,Sql Update,我在编写PostgreSQL请求时犯了一个愚蠢的错误。语法似乎完全错误,但仍有一半的效果 我有这个表(订户): 还有其他行,但它们是唯一相关的行(具有相同的设备\u id) 我提出请求: UPDATE subscriber SET invert = false WHERE device_id = (SELECT device_id WHERE id = 1) RETURNING *; 我忘记了子选择的子句中的。子系统按预期选择自身崩溃(设备\u id不存在)。但是,完整请求将计算并
设备\u id
)
我提出请求:
UPDATE subscriber
SET invert = false
WHERE device_id = (SELECT device_id WHERE id = 1)
RETURNING *;
我忘记了子选择的子句中的。子系统按预期选择自身崩溃(设备\u id不存在
)。但是,完整请求将计算并更新并返回其中一行(id为1的行)。正确的请求应该更新并返回两行
为什么??是某种虫子吗?或者子选择的行为是否与选择不同 我想以前也有人问过类似的问题,但我现在找不到
在子查询中,从外部查询中选择所有内容也是可见的。如果子选择中存在名称冲突,“本地”标识符优先于“外部”标识符。如果标识符在子选择中无效,但在外部查询中可用,则使用外部查询中的标识符
Postgres允许SELECT语句不带FROM
子句,因此
select 42;
有效
因此,您的子选择实际上使用了正在更新的表中的device\u id
和id
列。这就是查询工作的原因
这不是一个bug,这些可见性规则是SQL标准所要求的(但是,运行SELECT
而不运行FROM
是对SQL标准的扩展)。恐怕,跳过FROM
您在括号中创建的表达式是一个相关的子查询,而不仅仅是子查询,例如:
t=# select oid,(select oid) from pg_database limit 2;
oid | oid
-------+-------
1 | 1
12945 | 12945
(2 rows)
通过这种方式,Postgres尝试猜测列名使用的别名,在我的例子中,这是pg_数据库的别名。。。因此,在本例中,您的where device_id=(选择device_id where id=1)
在逻辑上等于where id=1
另一个例子:
t=# select oid,(select oid::int*2 where oid=1),2 from pg_database limit 2;
oid | ?column? | ?column?
-------+----------+----------
1 | 2 | 2
12945 | | 2
(2 rows)
这是查询背后的一些奇怪的边缘逻辑。我不能不同意在您的update语句中这样的逻辑令人困惑:)
t=# select oid,(select oid::int*2 where oid=1),2 from pg_database limit 2;
oid | ?column? | ?column?
-------+----------+----------
1 | 2 | 2
12945 | | 2
(2 rows)