也许写一个答案(侧重于@mathguy 对缺失连接特异性的观察,以及 SELECT 列与 GROUP BY/HAVING 的混合不适合)更好地找出您的问题并给出想法如何加强问题 ;-) ...下次我建议对这个问题更加重视,这样世界就不必在答案上如此繁重了。
我不认为这是 MySQL、Oracle 或不是数据库特定的问题,而是更多 SQL 初学者的学习之旅……您可能还想在这里寻找连接解释:"Difference between Inner Join & Full join"
从问题中给出的最小信息子集开始:2 表艺术家和作品相关的推测可能通过共享 ID(比如艺术家 ID)。
在 PostgreSQL 或 ParStream 等数据库中直接提出问题的一件事是选择分组中的列,查询既不分组也不聚合/过滤。但是我们开始了:
创建表:
$psql> CREATE TABLE artist(artist_id INT, given_name VARCHAR(42), family_name VARCHAR(99));
CREATE TABLE
$psql> CREATE TABLE work(work_id INT, artist_id INT, title VARCHAR(42));
CREATE TABLE
插入一些数据:
$psql> INSERT INTO artist VALUES(1, 'John', 'Doe');
INSERT 0 1
$psql> INSERT INTO artist VALUES(2, 'Natalie', 'Noir');
INSERT 0 1
$psql> INSERT INTO work VALUES(43, 1, 'The game is on');
INSERT 0 1
$psql> INSERT INTO work VALUES(44, 1, 'The game is over');
INSERT 0 1
$psql> INSERT INTO work VALUES(98, 2, 'La nuit commonce');
INSERT 0 1
$psql> INSERT INTO work VALUES(97, 2, 'Un jour se lve');
INSERT 0 1
检查里面有什么:
$psql> SELECT * FROM work;
work_id | artist_id | title
---------+-----------+------------------
43 | 1 | The game is on
44 | 1 | The game is over
98 | 2 | La nuit commonce
97 | 2 | Un jour se lve
(4 rows)
$psql> SELECT * FROM artist;
artist_id | given_name | family_name
-----------+------------+-------------
1 | John | Doe
2 | Natalie | Noir
(2 rows)
显示隐式 INNER JOIN:
$psql> SELECT * FROM work W, artist A;
work_id | artist_id | title | artist_id | given_name | family_name
---------+-----------+------------------+-----------+------------+-------------
43 | 1 | The game is on | 1 | John | Doe
43 | 1 | The game is on | 2 | Natalie | Noir
44 | 1 | The game is over | 1 | John | Doe
44 | 1 | The game is over | 2 | Natalie | Noir
98 | 2 | La nuit commonce | 1 | John | Doe
98 | 2 | La nuit commonce | 2 | Natalie | Noir
97 | 2 | Un jour se lve | 1 | John | Doe
97 | 2 | Un jour se lve | 2 | Natalie | Noir
(8 rows)
显示带有虚拟条件的显式 INNER JOIN 以让解析器通过我们的查询(更新:不要在家里使用它,只是为了显示混搭。):
$psql> SELECT * FROM work W INNER JOIN artist A ON 1 = 1;
work_id | artist_id | title | artist_id | given_name | family_name
---------+-----------+------------------+-----------+------------+-------------
43 | 1 | The game is on | 1 | John | Doe
43 | 1 | The game is on | 2 | Natalie | Noir
44 | 1 | The game is over | 1 | John | Doe
44 | 1 | The game is over | 2 | Natalie | Noir
98 | 2 | La nuit commonce | 1 | John | Doe
98 | 2 | La nuit commonce | 2 | Natalie | Noir
97 | 2 | Un jour se lve | 1 | John | Doe
97 | 2 | Un jour se lve | 2 | Natalie | Noir
(8 rows)
现在一个更有用的 INNER JOIN 仅匹配两个表中的这些条目,它们通过“创建者”关系相关:
$psql> SELECT * FROM work W INNER JOIN artist A ON W.artist_id = A.artist_id;
work_id | artist_id | title | artist_id | given_name | family_name
---------+-----------+------------------+-----------+------------+-------------
43 | 1 | The game is on | 1 | John | Doe
44 | 1 | The game is over | 1 | John | Doe
98 | 2 | La nuit commonce | 2 | Natalie | Noir
97 | 2 | Un jour se lve | 2 | Natalie | Noir
(4 rows)
所以上面我们盲目地相信数据管理部分会神奇地输入artist_id 值总是正确并符合我们的期望(在现实生活中,REFERENCES 外键约束肯定会放在工作表中的列上(没有艺术家/创作者就没有工作会规定艺术家表是因果关系的“第一”)。
您还看到,从表列表中进行选择与没有任何约束的 INNER JOIN 相同,即表中所有条目的笛卡尔积与表艺术家中的所有条目一起使用。
现在您的查询(为最小表模型编辑了一点)除了我在其请求想法中不清楚之外,还出现了错误,如本答案文本顶部所述:
$psql> SELECT W.work_id, W.title, W.artist_id, A.given_name, A.family_name FROM work W, artist A GROUP BY W.artist_id, A.given_name, A.family_name HAVING COUNT(*) > 1;
ERROR: column "w.work_id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT W.work_id, W.title, W.artist_id, A.given_name, A.fam...
这当然不能通过使用更有意义的连接输入集来解决(claro,因为错误指向 select 和 group by 列表中的不匹配:
$psql> SELECT W.work_id, W.title, W.artist_id, A.given_name, A.family_name FROM work W INNER JOIN artist A ON W.artist_id = A.artist_id GROUP BY W.artist_id, A.given_name, A.family_name HAVING COUNT(*) > 1;
ERROR: column "w.work_id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT W.work_id, W.title, W.artist_id, A.given_name, A.fam...
您需要就您想要达到的目标提出建议,以获得单一答案(有效)。在您这样做之前,这里有一些产品:
鉴于您仅加入现有的艺术家和作品 ID 对,您不需要该拥有子句,因为不存在的艺术家、缺失的作品或缺失的艺术家和作品的组合都不会进入您的查询所针对的行集,所以:
$psql> SELECT title, R.* FROM ( SELECT W.work_id AS work_id_filtered, W.artist_id, A.given_name, A.family_name FROM work W INNER JOIN artist A ON W.artist_id = A.artist_id GROUP BY W.work_id, W.artist_id, A.given_name, A.family_name) R INNER JOIN work WW ON WW.work_id = R.work_id_filtered;
title | work_id_filtered | artist_id | given_name | family_name
------------------+------------------+-----------+------------+-------------
The game is on | 43 | 1 | John | Doe
The game is over | 44 | 1 | John | Doe
La nuit commonce | 98 | 2 | Natalie | Noir
Un jour se lve | 97 | 2 | Natalie | Noir
(4 rows)
这应该会让您有点笨拙,但对于我周日早上的所有标题(非分组文件)的漂亮列表以及来自内部查询的分组字段来说已经足够了。格式化查询可以写成:
SELECT title,
R.*
FROM
(SELECT W.work_id AS work_id_filtered,
W.artist_id,
A.given_name,
A.family_name
FROM
work W
INNER JOIN artist A ON W.artist_id = A.artist_id
GROUP BY W.work_id,
W.artist_id,
A.given_name,
A.family_name) R
INNER JOIN
work WW ON WW.work_id = R.work_id_filtered;
删除任何 GROUP BY(直到问题详细说明为什么任务需要它):
$psql> SELECT W.work_id, W.title, W.artist_id, A.given_name, A.family_name FROM work W INNER JOIN artist A ON W.artist_id = A.artist_id;
work_id | title | artist_id | given_name | family_name
---------+------------------+-----------+------------+-------------
43 | The game is on | 1 | John | Doe
44 | The game is over | 1 | John | Doe
98 | La nuit commonce | 2 | Natalie | Noir
97 | Un jour se lve | 2 | Natalie | Noir
(4 rows)
查询格式化为不必水平滚动:
SELECT W.work_id, W.title, W.artist_id, A.given_name, A.family_name
FROM work W INNER JOIN artist A ON W.artist_id = A.artist_id;
注意:是的,正如@ThorstenKettner 正确指出的那样,我编造了“FULL INNER JOIN”这个词,对不起。也许我的大脑需要笛卡尔填充来平衡 LEFT|RIGHT|FULL OUTER JOIN - 谁知道 ;-)