UFN_CONFLICTCHECK_GETRESOURCECONFLICTSFORMULTIPLETIMES

For a large amount of non overlapping events with dates, return all events with resource conflicts.

Return

Return Type
table

Parameters

Parameter Parameter Type Mode Description
@EVENTDATES xml IN
@RESOURCES xml IN

Definition

Copy


        CREATE function dbo.UFN_CONFLICTCHECK_GETRESOURCECONFLICTSFORMULTIPLETIMES
        (
            @EVENTDATES xml,
            @RESOURCES xml
        )
        returns @CONFLICTS TABLE
        (
            EVENTID uniqueidentifier
        )
        as
        begin 

            declare @EVENTDATESTABLE table
            (
                EVENTID uniqueidentifier,
                STARTDATETIME datetime,
                ENDDATETIME datetime
            )

            insert into @EVENTDATESTABLE
            select
                T.c.value('(EVENTID)[1]','uniqueidentifier') as 'EVENTID',
                T.c.value('(STARTDATETIME)[1]','datetime') as 'STARTDATETIME',
                T.c.value('(ENDDATETIME)[1]','datetime') as 'ENDDATETIME'
            from @EVENTDATES.nodes('/EVENTDATES/ITEM') T(c)

            declare @RESOURCESTABLE table
            (
                RESOURCEID uniqueidentifier,
                QUANTITYNEEDED int
            )

            insert into @RESOURCESTABLE
            (RESOURCEID, QUANTITYNEEDED)
            select
                T.c.value('(RESOURCEID)[1]','uniqueidentifier'),
                T.c.value('(QUANTITYNEEDED)[1]','int')
            from @RESOURCES.nodes('/RESOURCES/ITEM') T(c)

            -- Don't worry about per ticket resources on events

            -- Or consumable resources

            delete from @RESOURCESTABLE 
            where 
                QUANTITYNEEDED = 0 or
                RESOURCEID in
                (
                    select ID 
                    from dbo.RESOURCE
                    where RESOURCE.TYPECODE <> 0
                )

            if (select count(1) from @RESOURCESTABLE) = 0
                return;

            -- Build a table to store resource counts

            declare @RESOURCESUSED table
            (
                SUPEREVENTID uniqueidentifier,
                EVENTID uniqueidentifier,
                ITINERARYID uniqueidentifier,
                ITINERARYITEMID uniqueidentifier,
                RESOURCEID uniqueidentifier,
                QUANTITYNEEDED int,
                STARTDATETIME datetime,
                ENDDATETIME datetime
            )

            insert into @RESOURCESUSED
            (
                SUPEREVENTID, 
                EVENTID,
                ITINERARYID,
                ITINERARYITEMID,
                RESOURCEID, 
                QUANTITYNEEDED,
                STARTDATETIME,
                ENDDATETIME
            )
            select 
                EVENTDATES.EVENTID as SUPEREVENTID,
                RESOURCES.EVENTID,
                RESOURCES.ITINERARYID,
                RESOURCES.ITINERARYITEMID,
                RESOURCES.RESOURCEID,
                RESOURCES.QUANTITYNEEDED,
                RESOURCES.STARTDATETIME,
                RESOURCES.ENDDATETIME
            from
            (
                select
                    EVENT.ID as EVENTID,
                    null as ITINERARYID,
                    null as ITINERARYITEMID,
                    EVENTRESOURCE.RESOURCEID as RESOURCEID,
                    EVENTRESOURCE.QUANTITYNEEDED as QUANTITYNEEDED,
                    EVENT.STARTDATETIME as STARTDATETIME,
                    EVENT.ENDDATETIME as ENDDATETIME
                from dbo.EVENT
                inner join dbo.EVENTRESOURCE on EVENT.ID = EVENTRESOURCE.EVENTID
                left outer join dbo.PROGRAM on 
                    EVENT.PROGRAMID = PROGRAM.ID
                inner join @RESOURCESTABLE as EVENTRESOURCECONFLICT on 
                    EVENTRESOURCECONFLICT.RESOURCEID = EVENTRESOURCE.RESOURCEID
                where 
                    (PROGRAM.ISACTIVE = 1 or EVENT.PROGRAMID is null)

                union all

                --  itinerary items


                select 
                    null as EVENTID,
                    null as ITINERARYID,
                    ITINERARYITEM.ID as ITINERARYITEMID,
                    ITINERARYITEMRESOURCE.RESOURCEID as RESOURCEID,
                    case RESOURCE.ISPERTICKETITEM
                        when 0 then
                            ITINERARYITEMRESOURCE.QUANTITYNEEDED
                        else
                            dbo.UFN_RESOURCE_CALCULATEPERTICKETQUANTITY_2(COALESCE((select sum(ITINERARYATTENDEE.QUANTITY) from dbo.ITINERARYATTENDEE where ITINERARYATTENDEE.ITINERARYID = ITINERARY.ID),0) * ITINERARYITEMRESOURCE.PERTICKETQUANTITY, ITINERARYITEMRESOURCE.PERTICKETDIVISOR)
                    end as QUANTITYNEEDED,
                    ITINERARYITEM.STARTDATETIME as STARTDATETIME,
                    ITINERARYITEM.ENDDATETIME as ENDDATETIME
                from dbo.ITINERARYITEM
                inner join dbo.ITINERARY on 
                    ITINERARYITEM.ITINERARYID = ITINERARY.ID
                inner join dbo.SALESORDER on
                    ITINERARY.RESERVATIONID = SALESORDER.ID
                inner join dbo.ITINERARYITEMRESOURCE on 
                    ITINERARYITEM.ID = ITINERARYITEMRESOURCE.ITINERARYITEMID
                inner join dbo.RESOURCE on 
                    ITINERARYITEMRESOURCE.RESOURCEID = RESOURCE.ID 
                inner join @RESOURCESTABLE as EVENTRESOURCECONFLICT on 
                    EVENTRESOURCECONFLICT.RESOURCEID = ITINERARYITEMRESOURCE.RESOURCEID
                where 
                    SALESORDER.STATUSCODE <> 5 and -- Make sure the reservation is not cancelled, cancelled resources do not count against total

                    ITINERARYITEM.INVALIDREASONCODE = 0 and -- Make sure that the itinerary item does not have an invalid reason

                    ITINERARYITEM.ITEMTYPECODE <> 3 -- Make sure the itinerary item is showing as scheduled


                union all

                -- itineraries 

                select 
                    null as EVENTID,
                    ITINERARY.ID as ITINERARYID,
                    null as ITINERARYITEMID,
                    ITINERARYRESOURCE.RESOURCEID as RESOURCEID,
                    case RESOURCE.ISPERTICKETITEM
                        when 0 then
                            ITINERARYRESOURCE.QUANTITYNEEDED
                        else
                            dbo.UFN_RESOURCE_CALCULATEPERTICKETQUANTITY_2(COALESCE((select sum(ITINERARYATTENDEE.QUANTITY) from dbo.ITINERARYATTENDEE where ITINERARYATTENDEE.ITINERARYID = ITINERARYRESOURCE.ITINERARYID),0) * ITINERARYRESOURCE.PERTICKETQUANTITY, ITINERARYRESOURCE.PERTICKETDIVISOR)
                    end as QUANTITYNEEDED,
                    ITINERARY.STARTDATETIME as STARTDATETIME,
                    ITINERARY.ENDDATETIME as ENDDATETIME
                from dbo.ITINERARY
                inner join dbo.SALESORDER on
                    ITINERARY.RESERVATIONID = SALESORDER.ID
                inner join dbo.ITINERARYRESOURCE on 
                    ITINERARY.ID = ITINERARYRESOURCE.ITINERARYID
                inner join dbo.RESOURCE on 
                    ITINERARYRESOURCE.RESOURCEID = RESOURCE.ID
                inner join @RESOURCESTABLE as EVENTRESOURCECONFLICT on 
                    EVENTRESOURCECONFLICT.RESOURCEID = ITINERARYRESOURCE.RESOURCEID
                where
                    SALESORDER.STATUSCODE <> 5 -- Make sure the reservation is not cancelled, cancelled resources do not count against total

            ) as RESOURCES
            inner join @EVENTDATESTABLE as EVENTDATES on
            (
                (EVENTDATES.STARTDATETIME >= RESOURCES.STARTDATETIME and EVENTDATES.STARTDATETIME < RESOURCES.ENDDATETIME) or
                (EVENTDATES.ENDDATETIME > RESOURCES.STARTDATETIME and EVENTDATES.ENDDATETIME <= RESOURCES.ENDDATETIME) or
                (EVENTDATES.STARTDATETIME < RESOURCES.STARTDATETIME and EVENTDATES.ENDDATETIME > RESOURCES.ENDDATETIME)
            )

            declare @CURRENTUSEDRESOURCES table
            (
                SUPEREVENTID uniqueidentifier,
                EVENTID uniqueidentifier,
                ITINERARYITEMID uniqueidentifier,
                ITINERARYID uniqueidentifier,
                RESOURCEID uniqueidentifier,
                QUANTITYNEEDED int
            )                

            declare @THISSUPEREVENTID uniqueidentifier
            declare @THISITINERARYID uniqueidentifier
            declare @THISITINERARYITEMID uniqueidentifier
            declare @THISEVENTID uniqueidentifier
            declare @THISRESOURCEID uniqueidentifier
            declare @THISQUANTITYNEEDED int
            declare @THISTIME datetime
            declare @THISISSTARTTIME bit

            declare @CURRENTEVENTID uniqueidentifier

            declare CONFLICTS_CURSOR cursor local fast_forward for
            select
                SUPEREVENTID,
                ITINERARYID,
                ITINERARYITEMID,
                EVENTID,
                RESOURCEID,
                QUANTITYNEEDED,
                TIME,
                ISSTARTTIME
            from
            (
                select
                    SUPEREVENTID,
                    ITINERARYID,
                    ITINERARYITEMID,
                    EVENTID,
                    RESOURCEID,
                    QUANTITYNEEDED,
                    STARTDATETIME as TIME,
                    1 as ISSTARTTIME
                from @RESOURCESUSED

                union all

                select
                    SUPEREVENTID,
                    ITINERARYID,
                    ITINERARYITEMID,
                    EVENTID,
                    RESOURCEID,
                    QUANTITYNEEDED,
                    ENDDATETIME as TIME,
                    0 as ISSTARTTIME
                from @RESOURCESUSED
            ) as T
            order by T.SUPEREVENTID, T.TIME, T.ISSTARTTIME

            open CONFLICTS_CURSOR;

            fetch next from CONFLICTS_CURSOR
            into 
                @THISSUPEREVENTID,
                @THISITINERARYID
                @THISITINERARYITEMID
                @THISEVENTID
                @THISRESOURCEID,
                @THISQUANTITYNEEDED,
                @THISTIME,
                @THISISSTARTTIME;

            while @@FETCH_STATUS = 0
            begin

                if @CURRENTEVENTID is null
                    set @CURRENTEVENTID = @THISSUPEREVENTID

                -- Reset current event if we are switching events, this is because we are going through 

                -- multiple events on conflict checking, ordered by eventid

                if @CURRENTEVENTID <> @THISSUPEREVENTID
                begin
                    delete from @CURRENTUSEDRESOURCES
                    set @CURRENTEVENTID = @THISEVENTID
                end

                if @THISISSTARTTIME = 1
                -- PUSH

                begin
                    insert into @CURRENTUSEDRESOURCES
                    (
                        EVENTID,
                        ITINERARYITEMID,
                        ITINERARYID,
                        RESOURCEID,
                        QUANTITYNEEDED
                    )
                    values
                    (
                        @THISEVENTID,
                        @THISITINERARYITEMID,
                        @THISITINERARYID,
                        @THISRESOURCEID,
                        @THISQUANTITYNEEDED
                    );

                    -- If in conflict, dump @CURRENTUSEDRESOURCES into @CONFLICTS

                    -- Not inserting duplicates


                    with RESOURCETOTAL_CTE as
                    (
                        select
                            RESOURCEID,
                            sum(QUANTITYNEEDED) as QUANTITYNEEDED,
                            count(RESOURCEID) as RESOURCECOUNT
                        from
                        (
                            select
                                RESOURCEID,
                                QUANTITYNEEDED
                            from @CURRENTUSEDRESOURCES

                            union all

                            select
                                RESOURCEID,
                                QUANTITYNEEDED
                            from @RESOURCESTABLE                        
                        ) as T
                        group by T.RESOURCEID
                    )                    
                    insert into @CONFLICTS
                    (
                        EVENTID
                    )
                    select 
                        @THISSUPEREVENTID
                    from @CURRENTUSEDRESOURCES as RESOURCESUSED
                    inner join RESOURCETOTAL_CTE RESOURCETOTAL on
                        RESOURCETOTAL.RESOURCEID = RESOURCESUSED.RESOURCEID
                    inner join dbo.RESOURCE on
                        RESOURCESUSED.RESOURCEID = RESOURCE.ID 
                    where 
                        not exists
                        (
                            select 1 from @CONFLICTS
                            where
                                [@CONFLICTS].EVENTID = @THISSUPEREVENTID
                        ) and
                        RESOURCETOTAL.QUANTITYNEEDED > RESOURCE.QUANTITY and
                        RESOURCETOTAL.RESOURCECOUNT > 1

                end
                else
                -- POP

                -- Do not need to check for conflicts as we are actually decrementing the count

                begin
                    delete from @CURRENTUSEDRESOURCES
                    where
                    (
                        @THISEVENTID = [@CURRENTUSEDRESOURCES].EVENTID or
                        @THISITINERARYITEMID = [@CURRENTUSEDRESOURCES].ITINERARYITEMID or
                        @THISITINERARYID = [@CURRENTUSEDRESOURCES].ITINERARYID
                    ) and
                    @THISRESOURCEID = [@CURRENTUSEDRESOURCES].RESOURCEID
                end

                fetch next from CONFLICTS_CURSOR
                into 
                    @THISSUPEREVENTID,
                    @THISITINERARYID
                    @THISITINERARYITEMID
                    @THISEVENTID
                    @THISRESOURCEID,
                    @THISQUANTITYNEEDED,
                    @THISTIME,
                    @THISISSTARTTIME;
            end

            close CONFLICTS_CURSOR;
            deallocate CONFLICTS_CURSOR;

            return;
        end