Home > Back-end >  SQL Server 2019 : Subquery Join won't execute
SQL Server 2019 : Subquery Join won't execute

Time:01-25

I have to design a report which will be a list of a bunch of overlapping data from the same table.

I have to start with the Project table because for the report @ProjectId is the only thing you get as an anchor.

In the RessourceBookings table are all bookings and some are overlapping like

  • Project A books resource B 24.01., 10 a.m. to 6 p.m.
  • Project C books resource B 24.01., 11 a.m. to 1 p.m
  • Project D books resource B 24.01., 1 p.m. to 4 p.m

These are the one I have to filter for and list all those booking conflicts for Project A.

This is the code I came up with at the moment. I didn't shorten it because I want to show that there are a few dependencies from some tables, which makes it a bit complicated (at least for me). If there are other parts besides the main problem which could be optimised, I would be happy to learn.

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

My goal is something like:

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 [...]

Without the whole q2 parts, it works well to list all the information for Project A.

The errors are:

Wrong syntax near the WHERE-keyword.. Native error: 156. SQLSTATE: 42000. Severity 15. Msg State 1. Line 76.

Wrong syntax near ">".. Native error: 102. SQLSTATE: 42000. Severity 15. MsgState 1. Line 87.

Without the subquery join, it works well but I think I need that there. I've googled the last two days but can't find any solution. In my eyes it seems correct.

I can't change the tables or their content. I have to deal with the setup. So temporary tables are not an option (which maybe could help).

(But please no single-word technical-term-answers. I'm not a developer, I have just to work with these kind of things. I'm willing to learn but it's a bit hard without a professional background)



Edit: For clarifications, here is a picture of the table ResourceBookings (top) and bottom the "goal" of the query if @ProjectId = 8525

enter image description here

CodePudding user response:

Try this

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.Id as id2
                ,p2.Name
                ,upr2.DocumentName
                ,rb2.Start
                ,rb2.[End]
                ,rb2.IsOption
                ,rb2.id
                ,rb2.ProjectId as rb_pid
                ,count(rb2.id) as id_count
            FROM ResourceBookings rb2
            LEFT JOIN Projects p2 ON p2.Id = rb2.ProjectId
            LEFT JOIN Users upr2 ON upr2.Id = p2.ResponsibleUserId
            LEFT JOIN Resources r ON r.Id = rb2.ResourceId
            WHERE rb2.ResourceId = r.Id
                AND (
                    rb2.Start BETWEEN DateAdd(s, 1,rb2.Start) AND DateAdd(s,-1,rb2.[End])
                    OR rb2.[End] BETWEEN DateAdd(s, 1,rb2.Start) AND DateAdd(s,-1,rb2.[End])
                    OR DateAdd(s, 1,rb2.Start) BETWEEN rb2.Start AND rb2.[End]
                )
                group by p2.Id
                ,p2.Name
                ,upr2.DocumentName
                ,rb2.Start
                ,rb2.[End]
                ,rb2.IsOption
                ,rb2.id
                ,rb2.ProjectId 
            ) q2
on q2.rb_pid = p.Id

WHERE p.Id = @ProjectId
    AND rb.Start >= SysDateTime()
    AND ugrr.UserGroupId = 11
    AND q2.id_count > 1 

CodePudding user response:

Well tried far longer and it seems I was overcomplicating things with the subqeury.
Without it and with a few more Joins it works like a charm.

For clarifing why I "ignored" some of the tips I got:

  • INNER wasn't the right choice. It would mess with the results badly (probably because the tables aren't great designed and have many overlapping headers without correlation...)
  • [] instead of '' will probably the better choice after reading a bit more about it. Will fix that in the future in my querys.
  • The window functions seems powerfull and less resource-hungry and I will look into it but at this point I didn't fully understand them well enough.

I think I will try to optimise it again after reading ad understanding more about the named tipps but for now this works for me:

DECLARE @ProjectId INT = 6290

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 'Resource-Name'
    ,r.Info AS 'Resource-Info'
    ,CASE WHEN ugrr.ResourceRoleId IN (4,7)
        THEN 0
        ELSE 1
        END AS 'Resource-Availability'
    ,rb.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'
    ,rb2.ProjectId AS 'Conflict-Project-ID'
    ,p2.Name AS 'Conflict-Project-Name'
    ,pc2.Name AS 'Conflict-Project-Color'
    ,upr2.DocumentName AS 'Conflict-Project-Responsible'
    ,rb2.Start AS 'Conflict-Start'
    ,rb2.[End] AS 'Conflict-End'
    ,pat2.Name AS 'Conflict-Booking-Action'
    ,rb2.IsOption AS 'Conflict-Booking-State' 
    ,rb2.Quantity AS 'Conflict-Booking-Quantity'

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
/* Doubles for Conflicts */
LEFT JOIN ResourceBookings rb2 ON rb2.ResourceId = rb.ResourceId
LEFT JOIN Projects p2 ON p2.Id = rb2.ProjectId
LEFT JOIN ProjectColors pc2 ON pc2.Id = p2.ProjectColorId
LEFT JOIN ProjectActions pa2 ON pa2.Id = rb2.ProjectActionId
LEFT JOIN ProjectActionTypes pat2 ON pat2.Id = pa2.ProjectActionTypeId
LEFT JOIN Users upr2 ON upr2.Id = p2.ResponsibleUserId

WHERE
    p.Id = @ProjectId
    AND rb.Start >= SysDateTime()
    AND ugrr.UserGroupId = 11
    AND rb.Id <> rb2.Id
    AND (
            (
                rb2.Start >= rb.Start
                AND rb2.Start <= rb.[End]
            )
        OR
            (
                rb2.[End] >= rb.Start
                AND rb2.[End] <= rb.[End]
            )
        OR
            (
                rb.Start >= rb2.Start
                AND rb.Start <= rb2.[End]
            )
        )
  •  Tags:  
  • Related