提问人:Andres SK 提问时间:11/16/2023 更新时间:11/16/2023 访问量:27
在MySQL中使用UNION无法正确组合行
Using UNION in MySQL is not properly combining the rows
问:
我有一个患者表 () 和 2 个表来跟踪他们在医疗常规控制中的身高和体重 (, )。kid
track_height
track_weight
- 在给定的月份,每种类型(身高和体重)可能有 1 次以上的测量。
- 有些月份可能根本没有测量值。
- 只有同时具有测量值(身高和体重)的月份才应在结果中显示。
- 如果在任何给定月份有多个任何类型的测量值,则需要对它们进行平均,以便每个测量值/每月最多只有一个结果。
这是我目前的查询:
(SELECT CONCAT(YEAR(track_height.date_track), '-', LPAD(MONTH(track_height.date_track), 2, 0)) AS date_track, ROUND(AVG(track_height.height), 1) AS height, NULL AS weight
FROM track_height
WHERE track_height.id_kid = 17
GROUP BY YEAR(track_height.date_track), MONTH(track_height.date_track)
ORDER BY track_height.date_track)
UNION
(SELECT CONCAT(YEAR(track_weight.date_track), '-', LPAD(MONTH(track_weight.date_track), 2, 0)) AS date_track, NULL AS height, ROUND(AVG(track_weight.weight), 1) AS weight
FROM track_weight
WHERE track_weight.id_kid = 17
GROUP BY YEAR(track_weight.date_track), MONTH(track_weight.date_track)
ORDER BY track_weight.date_track)
ORDER BY date_track
问题是它是这样呈现的:
它应该这样呈现:
如您所见,有 2 个具体问题需要解决:
- 该语句未按日期合并结果。必须只有一个 YYYY-MM 行,其中包含该月的身高和体重平均值。
UNION
- 在这种情况下,不应打印 2 月 (2023-02),因为我们缺少该月的体重跟踪数据。
我设置了一个 sqlfiddle 示例,但如果您想查看架构,这里是:
CREATE TABLE kid (
id_kid int(10) UNSIGNED NOT NULL,
date_insert timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
alias varchar(30) NOT NULL,
birthday date NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO kid (id_kid, date_insert, id_user, alias, gender, birthday, avatar) VALUES (17, '2023-10-22 17:19:08', 'Jenny', '2020-09-30');
CREATE TABLE track_height (
id_track int(10) UNSIGNED NOT NULL,
id_kid int(10) UNSIGNED NOT NULL,
date_track date NOT NULL,
height float UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO track_height (id_track, id_kid, date_track, height) VALUES (45, 17, '2023-04-07', 50), (46, 17, '2023-04-30', 52), (101, 17, '2023-01-31', 25), (102, 17, '2023-02-28', 34), (103, 17, '2023-03-31', 48), (104, 17, '2023-03-15', 42), (105, 17, '2023-03-01', 40), (106, 17, '2023-05-17', 55);
CREATE TABLE track_weight (
id_track int(10) UNSIGNED NOT NULL,
id_kid int(10) UNSIGNED NOT NULL,
date_track date NOT NULL,
weight float UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO track_weight (id_track, id_kid, date_track, weight) VALUES (34, 17, '2023-01-09', 9.6), (35, 17, '2023-01-18', 9.9), (36, 17, '2023-01-31', 10.1), (39, 17, '2023-03-07', 10.5), (40, 17, '2023-03-16', 10.6), (41, 17, '2023-04-05', 10.7), (42, 17, '2023-05-04', 11), (43, 17, '2023-05-30', 11.5);
感谢您的帮助!
答:
2赞
nullptr
11/16/2023
#1
这就是我会做的,
select date_format(h.date_track, "%Y-%m"),
round(avg(h.height), 1) as height,
round(avg(w.weight), 1) as weight
from track_height h inner join track_weight w
on h.id_kid = w.id_kid and month(h.date_track) = month(w.date_track)
group by month(h.date_track)
order by month(h.date_track);
内部联接将确保只考虑两个表中存在的月份。
你有什么理由使用“Union”吗?
评论
0赞
Andres SK
11/16/2023
没有特别的原因,只是两个表都具有同等代表性(这意味着没有“主”表)——这就是为什么我使用 UNION 而不是 JOIN 语句,但我看到你一针见血,查询抛出了确切的预期结果。不过,我对一些事情感到好奇。在我最初的查询中,应用 ROUND(AVG(), 1) 后,整数数字仍然没有小数......但在您提出的解决方案中,25 变为 25.0。有什么想法吗?谢谢!
0赞
Andres SK
11/16/2023
另外,我认为我需要在组声明中添加 和 ,否则每当我有更多来自多年的记录时,月份可能会在年份之间混淆(?ON h.id_kid = w.id_kid AND YEAR(h.date_track) = YEAR(w.date_track) AND MONTH(h.date_track) = MONTH(w.date_track)
GROUP BY YEAR(h.date_track), MONTH(h.date_track)
0赞
nullptr
11/17/2023
是的,您还需要在加入和分组多年和数月时添加一年。关于这一点,“应用 ROUND(AVG(), 1) 后,整数仍然没有小数......但在您提出的解决方案中,25 变为 25.0。知道为什么吗?我想,UNION 正在这样做,但我执行了您的个人查询,即使这样也没有给出小数点。不,我不知道为什么同一函数在不同的查询中有不同的行为。
评论
JOIN
UNION