【发布时间】:2022-01-24 14:59:46
【问题描述】:
我必须设计一个报告,该报告将是同一张表中一堆重叠数据的列表。
我必须从Project 表开始,因为对于报告,@ProjectId 是唯一作为锚点的东西。
RessourceBookings 表中是所有预订,有些是重叠的
- 项目 A 图书资源 B 24.01.,上午 10 点至下午 6 点
- 项目 C 图书资源 B 24.01.,上午 11 点到下午 1 点
- 项目 D 书籍资源 B 24.01., 1 p.m.到下午 4 点
这些是我必须过滤并列出项目 A 的所有预订冲突。
这是我目前想出的代码。我没有缩短它,因为我想表明某些表存在一些依赖关系,这使它有点复杂(至少对我而言)。如果除了主要问题还有其他可以优化的部分,我很乐意学习。
DECLARE @ProjectId INT = 8501
SELECT
p.Id AS 'Project-ID'
,p.Name AS 'Project-Name'
,p.Info AS 'Project-Info'
,pc.Name AS 'Project-Color'
,upr.DocumentName AS 'Project-Responsible'
,r.ResourceName AS 'Ressource-Name'
,r.Info AS 'Ressource-Info'
,CASE WHEN ugrr.ResourceRoleId IN (4,7)
THEN 0
ELSE 1
END AS 'Ressource-Availability'
,r.Quantity AS 'Booking-Quantity'
,rb.Start AS 'Booking-Start'
,rb.[End] AS 'Booking-End'
,pat.Name AS 'Booking-Action'
,rb.IsOption AS 'Booking-State'
,rb.OptionRequestAccepted AS 'Booking-Response'
,q2.ProjectId AS 'Conflict-Project-ID'
,q2.Name AS 'Conflict-Project-Name'
,q2.DocumentName AS 'Conflict-Project-Responsible'
,q2.Start AS 'Conflict-Start'
,q2.[End] AS 'Conflict-End'
,q2.IsOption AS 'Conflict-State'
FROM
Projects p
LEFT JOIN
ProjectColors pc ON pc.Id = p.ProjectColorId
LEFT JOIN
Users upr ON upr.Id = p.ResponsibleUserId
LEFT JOIN
ResourceBookings rb ON rb.ProjectId = p.Id
LEFT JOIN
Resources r ON r.Id = rb.ResourceId
LEFT JOIN
ProjectActions pa ON pa.Id = rb.ProjectActionId
LEFT JOIN
ProjectActionTypes pat ON pat.Id = pa.ProjectActionTypeId
LEFT JOIN
UserGroupResourceRoles ugrr ON ugrr.ResourceId = r.Id
LEFT JOIN
(SELECT
p2.ProjectId
,p2.Name
,upr2.DocumentName
,rb2.Start
,rb2.[End]
,rb2.IsOption
FROM
ResourceBookings rb2
LEFT JOIN
Projects p2 ON p2.Id = rb2.ProjectId
LEFT JOIN
Users upr2 ON upr2.Id = p2.ResponsibleUserId
WHERE
rb2.ResourceId = r.Id
AND (rb2.Start BETWEEN DATEADD(s, +1, rb.Start) AND DATEADD(s, -1, rb.[End])
OR rb2.[End] BETWEEN DATEADD(s, +1, rb.Start) AND DATEADD(s, -1, rb.[End])
OR DATEADD(s,+1,rb.Start) BETWEEN rb2.Start AND rb2.[End])) q2
WHERE
p.Id = @ProjectId
AND rb.Start >= SysDateTime()
AND ugrr.UserGroupId = 11
AND (SELECT Count(rb2.Id) - 1
FROM ResourceBookings rb2
WHERE rb2.ResourceId = r.Id
AND (rb2.Start BETWEEN DATEADD(s, +1, rb.Start) AND DATEADD(s, -1, rb.[End])
OR rb2.[End] BETWEEN DATEADD(s, +1, rb.Start) AND DATEADD(s, -1, rb.[End])
OR DATEADD(s, +1, rb.Start) BETWEEN rb2.Start AND rb2.[End])) > 0
我的目标是这样的:
| Project-ID | Project-Name | [...] | Conflict-Project-ID | Conflict-Project-Name | [...] |
|---|---|---|---|---|---|
| 1 | Project A | [...] | 2 | Project B | [...] |
| 1 | Project A | [...] | 3 | Project C | [...] |
| 1 | Project A | [...] | 4 | Project D | [...] |
没有整个 q2 部分,列出项目 A 的所有信息效果很好。
错误是:
WHERE 关键字附近的语法错误。本机错误:156。SQLSTATE:42000。严重性 15。消息状态 1。第 76 行。
“>”附近的语法错误。本机错误:102。SQLSTATE:42000。严重性 15。MsgState 1。第 87 行。
没有子查询连接,它工作得很好,但我想我需要那个。我在过去两天搜索了谷歌,但找不到任何解决方案。在我看来,这似乎是正确的。
我无法更改表格或其内容。我必须处理设置。所以临时表不是一种选择(这可能会有所帮助)。
(但请不要使用一个单词的技术术语答案。我不是开发人员,我只是从事这类工作。我愿意学习,但如果没有专业背景)
编辑: 为澄清起见,这里是表格
ResourceBookings(顶部)的图片,底部是查询的“目标”如果@ProjectId = 8525
【问题讨论】:
-
错误来自最后一个子查询。您不能在 where 子句中使用聚合函数,而是使用 count(q2.id)>1。为此,您需要在左连接子查询中添加 rb2.id ------ 而且您在最后一个左连接中缺少连接条件,它只是以 q2 结束并开始 where 子句开始。即使你修复了 where 问题,join 也会抛出错误
-
旁白:看来你的
LEFT JOINs 应该是INNER。您可能会发现使用窗口函数比使用子查询更好。BETWEENis a bad idea to use on dates. 使用[]引用列名,而不是'' -
@Charlieface 感谢您的回复!
INNER JOIN似乎就在那里,我会记住这一点。我无法理解你的意思You might find it better to use window functions rather than that subquery.使用[]然后''有什么区别? -
您可以使用窗口计数来实现与子查询相同的功能:
COUNT(*) OVER (PARTITION BY rb.ResourceId)或类似的东西。使用''引用列名是不好的,在某些情况下可能会导致意外结果,例如dba.stackexchange.com/questions/194224/…
标签: sql sql-server subquery left-join sql-server-2019