sql - Sql Left or Right Join 一对多分页
问题描述
我有一个主表,并通过左外连接或右外连接连接其他表。主表的一行有超过 30 行的连接查询结果。我尝试分页。但问题是我不知道它会为一个主表行结果返回多少行。
例子 :
主表第一行结果在我的查询中 40 行。主表第二行结果为 120 行。
问题(问题)更新: 对于分页,我需要给 pagesize 选择结果的计数。但我不知道我的选择结果的正确计数。示例我给第 1 页和第 50 页,因此我无法获得正确的结果。我需要为我的主表前 10 结果提供正确的页面大小。也许前 10 行的结果行数为 200,但我的页面大小为 50,这就是问题所在。
我正在使用 Sql 2014。我的 ASP.NET 项目需要它,但并不重要。
样本更新:
这就像搜索酒店进行预订。您的主桌是酒店桌。另一件事是(可媒体的)图像、(可媒体的)视频、(可放置的)位置和可能的(可评论的)评论,它们不止一行,并且与酒店有一对多的关系。对于一家酒店,所有信息的结果将是 100、50 或 10 行。我正在尝试对这个酒店结果进行分页。我需要在我的项目中获得 20 或 30 或 50 家酒店的性能。
示例查询更新:
SELECT
*
FROM
KisiselCoach KC
JOIN WorkPlace WP
ON KC.KisiselCoachId = WP.WorkPlaceOwnerId
JOIN Album A
ON KC.KisiselCoachId = A.AlbumId
JOIN Media M
ON A.AlbumId = M.AlbumId
LEFT JOIN Rating R
ON KC.KisiselCoachId = R.OylananId
JOIN FrUser Fr
ON KC.CoachId = Fr.UserId
JOIN UserJob UJ
ON KC.KisiselCoachId = UJ.UserJobOwnerId
JOIN Job J
ON UJ.JobId = J.JobId
JOIN UserExpertise UserEx
ON KC.KisiselCoachId = UserEx.UserExpertiseOwnerId
JOIN Expertise Ex
ON UserEx.ExpertiseId = Ex.ExpertiseId
Hotel Table :
HotelId HotelName
1 Barcelona
2 Berlin
Media Table :
MediaID MediaUrl HotelId
1 www.xxx.com 1
2 www.xxx.com 1
3 www.xxx.com 1
4 www.xxx.com 1
Location Table :
LocationId Adress HotelId
1 xyz, Berlin 1
2 xyz, Nice 1
3 xyz, Sevilla 1
4 xyz, Barcelona 1
Comment Table :
CommentId Comment HotelId
1 you are cool 1
2 you are great 1
3 you are bad 1
4 hmm you are okey 1
这只是样本!我的数据库中有 9999999 家酒店。想象一家酒店可能有 100 张图片,可能为零。我不能知道这一点。我需要在我的结果中获得 20 家酒店(分页)。但是 20 家酒店可能意味着 1000 行或 100 行。
解决方案
首先,您的查询对于表的可读性流/关系编写得不好。我已经更新并缩进以尝试显示表在层次相对论中的相关方式/位置。
你也想分页,让我们回到那个。您是否打算将每条记录显示为可能的项目,或者您是否打算显示“父”级别的数据集...例如,每个媒体、每个用户或其他只有一个实例,然后一旦该条目选择您将显示该实体的详细信息?如果是这样,我会在顶层做一个 DISTINCT 查询,或者至少抓住它必须在下一个级别显示的子记录计数(*)的几列。
此外,混合内连接、左连接和右连接可能会造成混淆。通常,右连接意味着您想要连接右表中的记录。是否可以将其重写为将所有必需的表都放在左侧,而不需要将其左连接到辅助表?
澄清所有这些关系肯定会有助于您尝试摆脱分页的上下文。我会检查评论,但如果冗长,我会编辑您的原始帖子问题,添加更多详细信息而不是长评论。
这是我的 SOMEWHAT 澄清查询重写为我认为关系在您的数据库中的内容。请注意我的缩进显示表 A -> B -> C -> D 的位置以便于阅读。所有这些都是(INNER)JOIN,表示它们都必须在所有相应的表之间匹配。如果某些东西并不总是存在,它们将被更改为 LEFT JOIN
SELECT
*
FROM
KisiselCoach KC
JOIN WorkPlace WP
ON KC.KisiselCoachId = WP.WorkPlaceOwnerId
JOIN Album A
ON KC.KisiselCoachId = A.AlbumId
JOIN Media M
ON A.AlbumId = M.AlbumId
LEFT JOIN Rating R
ON KC.KisiselCoachId = R.OylananId
JOIN FrUser Fr
ON KC.CoachId = Fr.UserId
JOIN UserJob UJ
ON KC.KisiselCoachId = UJ.UserJobOwnerId
JOIN Job J
ON UJ.JobId = J.JobId
JOIN UserExpertise UserEx
ON KC.KisiselCoachId = UserEx.UserExpertiseOwnerId
JOIN Expertise Ex
ON UserEx.ExpertiseId = Ex.ExpertiseId
查询的可读性对您自己和/或任何协助或关注您的人都有很大帮助。如果在相应的连接附近没有“on”子句,可能会非常令人困惑。
此外,这是您的 PRIMARY 表,其余的是查找参考表。
每条评论的补充
好的,所以我更新了一个查询,该查询似乎没有示例数据的上下文以及您在帖子中想要的内容。也就是说,我将从仅列出酒店列表和每家酒店的物品数量(*)开始,这样您就可以详细说明您拥有多少东西。就像是
select
H.HotelID,
H.HotelName,
coalesce( MedSum.recs, 0 ) as MediaItems,
coalesce( LocSum.recs, 0 ) as NumberOfLocations,
coalesce( ComSum.recs, 0 ) as NumberOfLocations
from
Hotel H
LEFT JOIN
( select M.HotelID,
count(*) recs
from Media M
group by M.HotelID ) MedSum
on H.HotelID = MedSum.HotelID
LEFT JOIN
( select L.HotelID,
count(*) recs
from Location L
group by L.HotelID ) LocSum
on H.HotelID = LocSum.HotelID
LEFT JOIN
( select C.HotelID,
count(*) recs
from Comment C
group by C.HotelID ) ComSum
on H.HotelID = ComSum.HotelID
order by
H.HotelName
--- apply any limit per pagination
现在这将返回顶层的每家酒店,以及每个酒店的物品总数,每个可能存在或不存在的个体计数,因此每个子检查都是 LEFT-JOIN。公开 20 家不同酒店的页面。现在,只要有人选择了一家酒店,您就可以深入了解该酒店的位置、媒体和评论。
现在,虽然这可以工作,但必须对每次查询进行这些计数可能会非常耗时。您可能希望将计数器列添加到您的主酒店表中,以表示在此处执行的计数。然后,通过一些每晚的过程,您可以重新更新一次计数,以使它们在所有历史记录中都做好准备,然后仅更新那些自上次输入日期以来有新活动的酒店的计数。不像您一天会有 1,000,000 条新图片、新地点、新评论的帖子,而是 22,000 条,那么这些是您需要重新更新计数的唯一酒店记录。每个增量周期都会很短,仅基于添加的最新条目。对于网络,有一些预聚合计数、总和等在可行的情况下可以节省大量时间。
推荐阅读
- c - 如何分配足够的内存来将 unsigned long long int 转换为字符串
- node.js - 强制文件链接以预览形式打开,而不是下载nodejs
- node.js - 在将数据从 nodejs 传递到 rust 时使用 neon 执行异步任务
- tensorflow - Pytorch -> [Onnx -> tensorflow] -> tflite 生成大量冗余的 conv2d 运算符
- r - ggplotly 从 ggplot 中删除误差线
- python - 无法通过 USB 串行 python 库与数字百分表通信
- react-native - 如何模拟 react-native-copilot?
- lodash - 如何使用包含选项创建 lodash 自定义构建?
- php - 通过 Moodle 数据库登录
- java - Spring bean 在扩展的类中为空