我有3个表:工作表,记录表,发布表
1个作品可以有多个录音,并且只有1个发行版中出现1个录音
表:工作
+---------+-----------+
| work_id | name |
+---------+-----------+
| 1 | Hello |
| 3 | Luna |
| 4 | Feel good |
| 5 | My self |
+---------+-----------+
表格:录制
+---------------------------------------------------------------------+
| recording_id | work_id | release_id | name | is_art | is_vid |
+---------------------------------------------------------------------+
| 45 | 1 | 45 | Hello4 | 1 | 0 |
| 78 | 3 | 67 | Luna5 | 1 | 0 |
| 23 | 5 | 128 | My self (r) | 1 | 0 |
| 95 | 5 | 156 | My self II | 1 | 0 |
| 17 | 4 | 67 | Luna67 | 1 | 0 |
+---------------------------------------------------------------------+
表:发布
+--------------------------------------------+
| release_id | name | year | month | day |
+--------------------------------------------+
| 45 | Yo | 1998 | 12 | NULL |
| 67 | Testing | 1967 | 3 | 3 |
| 128 | Maybe | 2018 | 10 | 21 |
| 156 | Again | 2018 | 10 | NULL |
+--------------------------------------------+
基本上,对于每个work
,我想返回recording
,其中is_art = 1
和is_vid = 0
并且release
是最旧的(最旧的年份,月和日期)。我可能是recording
release
可以具有相同的year
,month
和day
。在那种情况下,我想我需要找到一个唯一的标识符,所以请不要使用最新的release_id
结果集应如下所示:
+---------+---------------------------------------+
| work_id | name | recording_id | name |
+---------+---------------------------------------+
| 1 | Hello | 45 | Hello4 |
| 3 | Luna | 78 | Luna5 |
| 4 | Feel good | 17 | Luna67 |
| 5 | My self | 23 | My self (r)|
+---------+---------------------------------------+
到目前为止,我已经创建了此查询,但是老实说,作为一个新手,我知道这是完全错误的。它返回重复的行。我跌倒了,好像需要使用group by
和子查询,但是经过两天的搜索和测试工作之后,我无法创建解决方案……我发疯了
样本数据1
| work_id | work_name | recording_id | release_id | rec_name | year | month | day |
|---------|---------------------|--------------|------------|-----------------------------------------------------|------|-------|-----|
| 201 | Me ha dicho la luna | 253 | 5 | Me ha dicho la luna | 1998 | 4 | 22 |
| 201 | Me ha dicho la luna | 579 | 528 | Me ha dicho la luna (Moonlight Radio Edit) | 1998 | | |
| 201 | Me ha dicho la luna | 580 | 528 | Me ha dicho la luna (Luna llena Ambience Mix) | 1998 | | |
| 201 | Me ha dicho la luna | 581 | 528 | Me ha dicho la luna (Extended Callejuela's Version) | 1998 | | |
| 201 | Me ha dicho la luna | 582 | 528 | Me ha dicho la luna (Stoned Baby Free Version) | 1998 | | |
| 201 | Me ha dicho la luna | 252 | 1 | Me ha dicho la luna (con Chayanne) | 2006 | | |
样本数据2
| work_id | work_name | recording_id | release_id | rec_name | year | month | day |
|---------|------------|--------------|------------|---------------------------------------------------------|------|-------|-----|
| 401 | Si amanece | 397 | 26 | Si amanece | 1978 | 7 | 1 |
| 401 | Si amanece | 634 | 309 | Si amanece | 1978 | 7 | 1 |
| 401 | Si amanece | 396 | 257 | Si amanece (con el Mariachi Oro y Plata de Pepe Chávez) | 1979 | | |
| 401 | Si amanece | 564 | 188 | Si amanece | 2001 | | |
| 401 | Si amanece | 394 | 213 | Si amanece | 2001 | | |
| 401 | Si amanece | 395 | 1 | Si amanece | 2006 | | |
| 401 | Si amanece | 638 | 295 | Si amanece | | | |
答案 0 :(得分:2)
以下是为您的样本数据生成预期结果的查询:
select
w.work_id,
w.name work_name,
r.recording_id,
r.name recording_name
from work w
inner join recording r
on r.recording_id = (
select r1.recording_id
from recording r1
inner join releases l1 on l1.release_id = r1.release_id
where r1.work_id = w.work_id and r1.is_art = 1 and r1.is_vid = 0
order by -l1.year desc, -l1.month desc, -l1.day desc, r1.release_id desc
limit 1
)
通过使用相关子查询选择正确的行,将work
表与recording
结合起来,可以实现此目的。从示例数据和结果看来,您似乎想在对行顺序进行排序时将null
放在首位:这不是MySQL的默认行为,因此我们使用了一种技巧,其中包括按{{1} }(在将- <column_name> desc
放在升序的同时放在首位)。
注意:null
是reserved word in MySQL,所以我改名为release
表(否则,您需要用反引号将其括起来)。
work_id | work_name | recording_id | recording_name ------: | :-------- | -----------: | :------------- 1 | Hello | 45 | Hello4 3 | Luna | 78 | Luna5 5 | My self | 23 | My self (r)
或者,如果您正在运行MySQL 8.0,则使用releases
来标识正确的记录。根据您的数据集,这可能会或可能不会更好:
row_number()
Demo on DB Fiddle (与上述结果相同)
答案 1 :(得分:1)
每个recording
获取最新的work_id
,则可以使用聚合函数max()
,后跟group by
子句。
select w.work_id, w.name, r.recording_Id, r.name,
max(cast(concat(coalesce(year, '1000'), coalesce(month, '01'), coalesce(day, '01')) as date))
from work w
join recording r on w.work_id = r.work_id
join release rl on rl.release_id = r.release_id
where r.is_art = 1 and r.is_vid = 0
group by w.work_id, w.name, r.recording_Id, r.name
order by w.work_id
答案 2 :(得分:1)
这似乎得到了“正确”的答案:
-- Query 1
CREATE TEMPORARY TABLE t (
new_id INT AUTO_INCREMENT PRIMARY KEY
)
SELECT w.work_id,
w.name AS work_name,
rec.recording_id,
rec.release_id,
rec.name AS rec_name,
year, month, day
FROM work AS w
JOIN recording AS rec ON rec.work_id = w.work_id
JOIN releaset AS rel ON rel.release_id = rec.release_id
WHERE is_art = 1
AND is_vid = 0
ORDER BY work_id, year, month, day, release_id;
-- Query 2
SELECT work_id, work_name, recording_id, rec_name
FROM ( SELECT MIN(new_id) AS first_id FROM t
GROUP BY work_id, year, month, day, release_id ) AS x
JOIN t ON t.new_id = x.first_id;
不幸的是,它将在某些版本上失败。
MariaDB 10.2+将不会抱怨Can't reopen table: 't'
。有两种解决方法:使t
不是TEMPORARY
或将临时表复制到另一个临时表中。
MySQL 8.0和MariaDB 10.2+可以使用WITH
,以有效地重复使用临时表。但是,潜在的问题是需要向临时表中添加AUTO_INCREMENT
列。
好的,这是解决“重新打开”问题的方法:
-- Query 3
CREATE TEMPORARY TABLE x
SELECT MIN(new_id) AS first_id FROM t
GROUP BY work_id;
-- Query 4
SELECT work_id, work_name, recording_id, rec_name
FROM x
JOIN t ON t.new_id = x.first_id;
然后使用查询1,3,4。