Mysql 3个表在一对多上联接
我在学习连接时遇到一些困难,我正在处理2个一对多关系: 在这种情况下,我有许多章节和许多评级的小说 我需要获得小说信息,再加上与每部小说相关的章节数,以及每部小说的评分,我正在尝试:Mysql 3个表在一对多上联接,mysql,Mysql,我在学习连接时遇到一些困难,我正在处理2个一对多关系: 在这种情况下,我有许多章节和许多评级的小说 我需要获得小说信息,再加上与每部小说相关的章节数,以及每部小说的评分,我正在尝试: SELECT n.id , n.nvl_title , COUNT(c.id) AS nvl_chapters , AVG(nr.rate_value) as nvl_rating , MAX(c.createdAt) AS nvl_last_update FROM no
SELECT n.id
, n.nvl_title
, COUNT(c.id) AS nvl_chapters
, AVG(nr.rate_value) as nvl_rating
, MAX(c.createdAt) AS nvl_last_update
FROM novels n
left
JOIN novels_ratings nr
ON nr.novel_id = n.id
left
JOIN chapters c
ON c.nvl_id = n.id
AND c.chp_status = 'Active'
WHERE n.nvl_status IN ("Active", "Finished")
GROUP
BY n.id;
仅处理章节,查询似乎工作得很好,但如果我添加行“left JOIN Novelies\u ratings nr ON nr.Novely\u id=n.id”,章节计数将增加到小说的许多评级
例如:一本有两章和两个等级的小说总共返回4章
我们将非常感谢您的帮助
如果有什么我想解释的,请告诉我,我会尽力澄清
我正在使用一些丑陋的查询来完成这项工作,但一旦章节表开始有许多寄存器,我就不得不学习更多的光学查询
编辑
我创建了一个小数据库,足以对查询进行一些测试:
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";
CREATE TABLE `chapters` (
`id` int(11) NOT NULL,
`nvl_id` int(20) DEFAULT NULL,
`chp_title` varchar(250) DEFAULT NULL,
`chp_status` varchar(8) NOT NULL DEFAULT 'Active',
`createdAt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
INSERT INTO `chapters` (`id`, `nvl_id`, `chp_title`, `chp_status`, `createdAt`) VALUES
(1, 1, 'generic chapter 1', 'Active', '0000-00-00 00:00:00'),
(2, 1, 'generic chapter 2', 'Active', '0000-00-00 00:00:00');
CREATE TABLE `novels` (
`id` int(20) NOT NULL,
`nvl_title` varchar(250) DEFAULT NULL,
`nvl_status` varchar(8) NOT NULL DEFAULT 'Active'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
INSERT INTO `novels` (`id`, `nvl_title`, `nvl_status`) VALUES
(1, 'generic novel', 'Active');
CREATE TABLE `novels_ratings` (
`id` int(20) NOT NULL,
`novel_id` int(20) DEFAULT NULL,
`rate_value` int(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
INSERT INTO `novels_ratings` (`id`, `novel_id`, `rate_value`) VALUES
(1, 1, 3),
(2, 1, 4);
ALTER TABLE `chapters`
ADD PRIMARY KEY (`id`);
ALTER TABLE `novels`
ADD PRIMARY KEY (`id`);
ALTER TABLE `novels_ratings`
ADD PRIMARY KEY (`id`);
ALTER TABLE `chapters`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
ALTER TABLE `novels`
MODIFY `id` int(20) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;
ALTER TABLE `novels_ratings`
MODIFY `id` int(20) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
COMMIT;
多谢各位 这是一个完整的解决方案(最终)。由于MySQL没有实现
完全连接
,因此解决方案使用左连接
与右连接
配对
你可以做:
with
r as (
select n.id, avg(nr.rate_value) as nvl_rating
from novels n
join novels_ratings nr on nr.novel_id = n.id
group by n.id
),
c as (
select n.id, count(c.id) as nvl_chapters, max(c.createdAt) as nvl_last_update
from novels n
join chapters c on c.nvl_id = n.id and c.chp_status = 'Active'
group by n.id
)
select r.id, r.nvl_rating, c.*
from r
left join c on c.id = r.id
UNION ALL
select c.id, r.nvl_rating, c.*
from r
right join c on c.id = r.id
where r.id is null
我认为最简单的方法是:
SELECT n.id, n.nvl_title,
COUNT(c.id) AS nvl_chapters,
(select AVG(nr.rate_value) from novels_ratings nr where nr.novel_id = n.id) as nvl_rating,
MAX(c.createdAt) AS nvl_last_update
FROM novels n
left JOIN chapters c ON c.nvl_id = n.id AND c.chp_status = 'Active'
WHERE n.nvl_status IN ("Active", "Finished")
GROUP BY n.id;
非常简单,而且它的性能也应该很好。您需要分别处理这两个聚合。并且您需要一个完全连接。。。MySQL还不支持这一点。可以这样做,但查询将很难看。您可以使用此网站了解有关加入的信息。这个网站用例子解释连接方法。谢谢你的回答,我已经看过很多关于连接的教程,但是我找不到一个答案,关于为什么我做了两个连接,一个连接到章节,另一个连接到评分,为什么章节与小说中的许多相关项目(章节和评分)有关。相信我,在stackoverflow中写一个问题永远是我在几个小时的努力后做的最后一件事@刺客。我怎样才能做到你所说的一切?@Andresplazamarkés你说得对。我终于有时间写下整个解决方案了。嗨@Marc谢谢你的回答,我以前试过这个,效果很好,但我担心的是,novel_ratings表可能会有数百个条目,使得查询中的另一个SELECT会降低查询性能,正如chapter表联接对我来说似乎是一种非常有效的方式,这就是为什么我坚持使用两个联接来实现此查询(如果可能的话)如果表的索引正确,则这不应是低效的查询。但是您可以通过查询临时表并在其上进行连接,以非常类似的方式进行连接。由你决定。非常感谢@The Impaler,它看起来非常有趣和有用,我将对这个查询进行一些测试,分享结果,如果它是正确的,将你标记为正确答案。