sql - 当我按键聚合时,为什么不能从“GROUP BY”中排除依赖列?
问题描述
如果我有以下表(作为使用 PostgreSQL 的示例,但可以是任何其他关系数据库),其中car
有两个键(id
和vin
):
create table car (
id int primary key not null,
color varchar(10),
brand varchar(10),
vin char(17) unique not null
);
create table appraisal (
id int primary key not null,
recorded date not null,
car_id int references car (id),
car_vin char(17) references car (vin),
price int
);
我可以在不聚合它们的情况下成功地将c.color
和包含c.brand
在选择列表中,因为它们依赖于c.id
:
select
c.id, c.color, c.brand,
min(price) as min_appraisal,
max(price) as max_appraisal
from car c
left join appraisal a on a.car_id = c.id
group by c.id; -- c.color, c.brand are not needed here
但是,以下查询失败,因为它不允许我在选择列表中包含c.color
和c.brand
,即使它确实取决于c.vin
表的(即键)。
select
c.vin, c.color, c.brand,
min(price) as min_appraisal,
max(price) as max_appraisal
from car c
left join appraisal a on a.car_vin = c.vin
group by c.vin; -- Why are c.color, c.brand needed here?
错误:错误:列“c.color”必须出现在 GROUP BY 子句中或用于聚合函数位置:18
DB Fiddle中的示例。
解决方案
GROUP BY
因为只有 PK 涵盖子句中基础表的所有列。因此,您的第一个查询有效。UNIQUE
约束没有。
不可延期UNIQUE
和NOT NULL
约束的组合也符合条件。但这并没有实现 - 以及 SQL 标准已知的一些其他功能依赖项。该功能的主要作者 Peter Eisentraut 有更多想法,但当时确定需求低且相关成本可能很高。请参阅pgsql-hackers 上有关该功能的讨论。
当
GROUP BY
存在或存在任何聚合函数时,列表表达式引用未分组列是无效的,SELECT
除非在聚合函数内或当未分组列在功能上依赖于分组列时,否则可能会有多个为未分组的列返回的值。如果分组列(或其子集)是包含未分组列的表的主键,则存在功能依赖性。
更明确地说:
GROUP BY
仅当表的主键包含在GROUP BY
列表中时,PostgreSQL 才识别功能依赖性(允许从 中省略列)。SQL 标准指定了应识别的附加条件。
由于c.vin
is UNIQUE NOT NULL
,您可以改用 PK 列来修复您的第二个查询:
...
group by c.id;
此外,虽然引用完整性被强制执行并查询整个表,但给定的两个查询都可以大大降低成本:在连接appraisal
之前聚合行。这消除了GROUP BY
对外部SELECT
先验的需要。喜欢:
SELECT c.vin, c.color, c.brand
, a.min_appraisal
, a.max_appraisal
FROM car c
LEFT JOIN (
SELECT car_vin
, min(price) AS min_appraisal
, max(price) AS max_appraisal
FROM appraisal
GROUP BY car_vin
) a ON a.car_vin = c.vin;
看:
有关的:
推荐阅读
- android - Android:如何进行多模块匕首组件注入?
- r - 将两列组合在一起并将其原始列名保留为单独的列
- python - Dash 应用程序没有错误,但没有绘图
- java - 如何在 JavaFX FXML 的窗格中编辑文本/图像/按钮
- wordpress - 显示 ACF 组中 Post Object 字段的数据
- elasticsearch - Elasticsearch 和 CAP 定理
- vbscript - vbscript:替换搜索字符串后的所有内联文本
- c++ - 无法从媒体会话中检索 IMFAudioPolicy
- unzip - 如何使用 Deflate64 压缩解压缩受密码保护的文件?我已经有密码了。在 python 或 vb.net 中
- python - Pycharm“无法使用创建进程”