The*_*can 18 mysql sql postgresql select duplicates
这是我的查询:
SELECT autor.entwickler,anwendung.name
FROM autor
left join anwendung
on anwendung.name = autor.anwendung;
entwickler | name
------------+-------------
Benutzer 1 | Anwendung 1
Benutzer 2 | Anwendung 1
Benutzer 2 | Anwendung 2
Benutzer 1 | Anwendung 3
Benutzer 1 | Anwendung 4
Benutzer 2 | Anwendung 4
(6 rows)
Run Code Online (Sandbox Code Playgroud)
我想为字段中的每个不同值保留一行name,并丢弃其他如下:
entwickler | name
------------+-------------
Benutzer 1 | Anwendung 1
Benutzer 2 | Anwendung 2
Benutzer 1 | Anwendung 3
Benutzer 1 | Anwendung 4
Run Code Online (Sandbox Code Playgroud)
在MySQL中,我会这样做:
SELECT autor.entwickler,anwendung.name
FROM autor
left join anwendung
on anwendung.name = autor.anwendung
GROUP BY anwendung.name;
Run Code Online (Sandbox Code Playgroud)
但是PostgreSQL给了我这个错误:
错误:列"autor.entwickler"必须出现在GROUP BY子句中或用于聚合函数LINE 1:SELECT autor.entwickler FROM autor left join anwendung on a ...
我完全理解错误并假设mysql实现比postgres实现更少SQL.但是我怎样才能得到理想的结果呢?
Cra*_*ger 35
PostgreSQL当前不允许含糊不清的GROUP BY语句,其结果取决于扫描表的顺序,使用的计划等.标准表示它应该如何工作AFAIK,但是一些数据库(如5.7之前的MySQL版本)允许更宽松查询只选择出现在SELECT列表中但不在列表中的元素遇到的第一个值GROUP BY.
在PostgreSQL中,您应该使用DISTINCT ON这种查询.
你想写下这样的东西:
SELECT DISTINCT ON (anwendung.name) anwendung.name, autor.entwickler
FROM author
left join anwendung on anwendung.name = autor.anwendung;
Run Code Online (Sandbox Code Playgroud)
(根据后续评论更正的语法)
这有点像MySQL 5.7的ANY_VALUE(...)伪函数group by,但相反 - 它表示distinct on子句中的值必须是唯一的,并且任何值都可以接受未指定的列.
除非有ORDER BY,否则没有保证选择哪些值.你通常应该有ORDER BY可预测性.
人们还注意到使用聚合物min()或者max()可以使用.虽然这是正确的 - 并且将导致可靠和可预测的结果,与使用DISTINCT ON或不太相似GROUP BY- 由于需要额外的排序或聚合而具有性能成本,并且它仅适用于序数数据类型.
Erw*_*ter 12
Craig的回答和你在评论中得到的查询共享同样的缺陷:表anwendung位于a的右侧LEFT JOIN,这与你明显的意图相矛盾.你关心anwendung.name并autor.entwickler 任意挑选.我会再回到那里了.
它应该是:
SELECT DISTINCT ON (1) an.name, au.entwickler
FROM anwendung an
LEFT JOIN autor au ON an.name = au.anwendung;
Run Code Online (Sandbox Code Playgroud)
DISTINCT ON (1)只是一种语法简写DISTINCT ON (an.name).这里允许进行位置参考.
如果entwicklerapp(anwendung)有多个developers(),则任意选择一个开发人员.ORDER BY如果你想要"第一个"(按字母顺序根据你的语言环境),你必须添加一个子句:
SELECT DISTINCT ON (1) an.name, au.entwickler
FROM anwendung an
LEFT JOIN autor au ON an.name = au.anwendung
ORDER BY 1, 2;
Run Code Online (Sandbox Code Playgroud)
正如@mdahlman暗示的那样,一种更规范的方式是:
SELECT an.name, min(au.entwickler) AS entwickler
FROM autor au
LEFT JOIN anwendung an ON an.name = au.anwendung
GROUP BY an.name;
Run Code Online (Sandbox Code Playgroud)
或者,更好的是,清理你的数据模型,实现多对多关系之间anwendung和autor正确,加代理主键作为anwendung和autor并不独特,强制关系的完整性与外键约束和适应您的结果查询:
CREATE TABLE autor (
autor_id serial PRIMARY KEY -- surrogate primary key
, autor text NOT NULL);
INSERT INTO autor VALUES
(1, 'mike')
, (2, 'joe')
, (3, 'jane') -- worked on two apps
, (4, 'susi'); -- has no part in any apps (yet)
CREATE TABLE anwendung (
anwendung_id serial PRIMARY KEY -- surrogate primary key
, anwendung text UNIQUE); -- disallow duplicate names
INSERT INTO anwendung VALUES
(1, 'foo') -- has 3 authors linked to it
, (2, 'bar')
, (3, 'shark')
, (4, 'bait'); -- has no authors attached to it (yet).
CREATE TABLE autor_anwendung ( -- you might name this table "entwickler"
autor_id integer REFERENCES autor ON UPDATE CASCADE ON DELETE CASCADE
, anwendung_id integer REFERENCES anwendung ON UPDATE CASCADE ON DELETE CASCADE
, PRIMARY KEY (autor_id, anwendung_id)
);
INSERT INTO autor_anwendung VALUES
(1, 1)
,(2, 1)
,(3, 1)
,(2, 2)
,(3, 3);
Run Code Online (Sandbox Code Playgroud)
此查询每个应用程序检索一行,其中一个关联作者(按字母顺序排列第一个),如果没有,则检索NULL:
SELECT DISTINCT ON (1) an.anwendung, au.autor
FROM anwendung an
LEFT JOIN autor_anwendung au_au USING (anwendung_id)
LEFT JOIN autor au USING (autor_id)
ORDER BY 1, 2;
Run Code Online (Sandbox Code Playgroud)
结果:
name | entwickler
-------+-----------------
bait |
bar | joe
foo | jane
shark | jane
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
30024 次 |
| 最近记录: |