Link to home
Start Free TrialLog in
Avatar of Philippe Renaud
Philippe RenaudFlag for Canada

asked on

Help with SQL Query

Hello EE,

I need to do a SQL Query.
I have a table called Closing_Date

in this table, the columns are:   Date, Description
For example, values can be :

07/01/2020  Canada Day
07/10/2020 Summer vacation
07/11/2020 Summer Vacation
07/12/2020 Summer Vacation
......
12/25/2020  Christmas
etc..


in another table, let's call it TABLE_A i have 4 columns :

JobNo, JobDate, NbDays, DeliveryDate


values for example can be :

001, 04/11/2019, 68, 02/01/2020
002  04/15/2020, 56, 08/01/2020
003, 05/05/2020, 68, 08/01/2020



My question is, and maybe you already see me coming with this question :

I need to get a "ResultDate" that will grab for a JobNo, the JobDate and add the NbDays to it and see if I go beyond the DelieveryDate. but WITHOUT counting the days in the Table Closing_Date.


so if we add 68 days to the JobDate, and it goes beyond 08/01/2020, well maybe its not true if we remove the dates in closing_date table, you follow ?


I hope my explanation is clear.....
Let me know guys..if you can do me a little query ?


thanks alot EE.
Avatar of Scott Pletcher
Scott Pletcher
Flag of United States of America image

Please try this:


 
;WITH 
cte_tally10 AS ( 
    SELECT * FROM (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) AS numbers(number) 
), 
cte_tally1000 AS ( 
    SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) - 1 AS number 
    FROM cte_tally10 c1 CROSS JOIN cte_tally10 c2 CROSS JOIN cte_tally10 c3 
) 
SELECT A.*, ca1.DeliveryDate 
FROM TABLE_A A 
CROSS APPLY ( 
    SELECT MAX(AllDates) AS DeliveryDate 
    FROM ( 
        SELECT TOP (A.NbDays) DATEADD(DAY, t.number, A.JobDate) AS AllDates 
        FROM cte_tally1000 t 
        WHERE 
            t.number BETWEEN 1 AND A.NbDays + 30 AND 
            NOT EXISTS ( 
                SELECT 1 
                FROM Closing_Date CD 
                WHERE CD.Date = DATEADD(DAY, t.number, A.JobDate) 
            ) 
        ORDER BY t.number 
    ) AS derived 
) AS ca1 
 

Open in new window

I would recommend implementing a true Calendar table and have a boolean column to indicate whether you are closed are not.  It saves a step.  Below is a possible solution that hopefully will help out.

DECLARE @Closing_Date TABLE
(
	[Date]			DATE			NOT NULL,
	[Description]	VARCHAR(500)	NOT NULL
);

INSERT @Closing_Date
(
    [Date],
    [Description]
)
VALUES
	('20200101', 'New Years Day'),
	('20200704', 'Independence Day'),
	('20200701', 'Canada Day'),
	('20200710', 'Closed'),
	('20200711', 'Closed'),
	('20200712', 'Closed'),
	('20201224', 'Christmas Eve'),
	('20201225', 'Christmas Day');

DECLARE @TableA TABLE
(
	JobNo			INT		NOT NULL,
	JobDate			DATE	NOT NULL,
	NBDays			INT		NOT NULL,
	DeliveryDate	DATE	NULL
);

INSERT @TableA
(
    JobNo,
    JobDate,
    NBDays,
    DeliveryDate
)
VALUES
	(1, '04/11/2019', 68, '02/01/2020'),
	(2, '04/15/2020', 56, '08/01/2020'),
	(3, '05/05/2020', 68, '08/01/2020');

WITH cteCalendar AS
(
	SELECT CAST('20190101' AS DATE) AS [Date]
	UNION ALL
	SELECT DATEADD(DAY, 1, [Date])
	FROM cteCalendar
	WHERE [Date] < '20211231'
),
cteClosedCalendar AS
(
	SELECT C.[Date],
		CASE WHEN CD.[Date] IS NOT NULL THEN 1 ELSE 0 END AS IsClosed
	FROM cteCalendar AS C
	LEFT OUTER JOIN @Closing_Date AS CD
		ON C.[Date] = CD.[Date]
),
cteJobCalendar AS
(
	SELECT Job.JobNo,
		Job.JobDate,
		Job.NBDays,
		Job.DeliveryDate,
		C.[Date] AS CalendarDate,
		C.Isclosed,
		ROW_NUMBER() OVER(PARTITION BY Job.JobNo, C.IsClosed ORDER BY C.[Date]) AS DateRowNumber
	FROM @TableA AS Job
	INNER JOIN cteClosedCalendar AS C
		ON Job.JobDate < C.[Date]
)
SELECT cteJobCalendar.JobNo,
	cteJobCalendar.JobDate,
	cteJobCalendar.NBDays,
	cteJobCalendar.DeliveryDate,
	cteJobCalendar.CalendarDate AS ResultDate,
	DATEADD(DAY, cteJobCalendar.NBDays, cteJobCalendar.JobDate) AS CalcResultDate
FROM cteJobCalendar
WHERE cteJobCalendar.IsClosed = 0
	AND cteJobCalendar.DateRowNumber = cteJobCalendar.NBDays
ORDER BY cteJobCalendar.CalendarDate
OPTION (MAXRECURSION 0);

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of slightwv (䄆 Netminder)
slightwv (䄆 Netminder)

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Creating Tables:
USE Dict
GO
CREATE TABLE Closing_Date ([Date] Date, [Description] NVarChar(200))
GO
CREATE TABLE TABLE_A(JobNo VarChar(3), JobDate Date, NbDays Int, DeliveryDate Date)
GO
INSERT INTO Closing_Date([Date],[Description]) VALUES
('07/01/2020', 'Canada Day'),
('07/10/2020', 'Summer vacation'),
('07/11/2020', 'Summer Vacation'),
('07/12/2020', 'Summer Vacation')
GO
INSERT INTO TABLE_A(JobNo, JobDate, NbDays, DeliveryDate) VALUES
('001', '04/11/2019', 68, '02/01/2020'),
('002', '04/15/2020', 56, '08/01/2020'),
('003', '05/05/2020', 68, '06/01/2020') -- It was changed for test
GO
SELECT * FROM Closing_Date
SELECT * FROM TABLE_A
GO

Calculating:

USE Dict
GO
DECLARE @JobNo VarChar(3), @JobDate Date, @NbDays Int,
@DeliveryDate Date, @CurrentDay Int, @FinishDate Date,
@WorkDays Int
DECLARE cr CURSOR LOCAL FAST_FORWARD READ_ONLY FOR
SELECT * FROM TABLE_A
OPEN cr
WHILE 1=1 BEGIN
      FETCH NEXT FROM cr INTO @JobNo, @JobDate, @NbDays, @DeliveryDate
      IF @@FETCH_STATUS <> 0 BREAK
      SET @CurrentDay = 0
      SET @WorkDays = 0
      WHILE @WorkDays < @NbDays BEGIN
            IF NOT Exists(
                  SELECT NULL FROM Closing_Date
                  WHERE [Date] = DateAdd(day, @CurrentDay, @JobDate)
            ) BEGIN
                  SET @WorkDays += 1
            END
            SET @CurrentDay += 1
      END
      SET @FinishDate = DateAdd(day, @CurrentDay, @JobDate)
      PRINT 'The job No: ['+@JobNo+']'
      PRINT '@JobDate = ' + Cast(@JobDate AS NVarChar)
      PRINT '@CurrentDay = ' + Cast(@CurrentDay AS NVarChar)
      PRINT '@WorkDays = ' + Cast(@WorkDays AS NVarChar)
      PRINT '@DeliveryDate = ' + Cast(@DeliveryDate AS NVarChar)
      PRINT '@FinishDate = ' + Cast(@FinishDate AS NVarChar)
      IF @FinishDate > @DeliveryDate BEGIN
            PRINT 'The job ['+@JobNo+'] will be finished after the Delivery Date:'
      END
      PRINT ' '
END
CLOSE cr
DEALLOCATE cr

Results:

The job No: [001]
@JobDate = 2019-04-11
@CurrentDay = 68
@WorkDays = 68
@DeliveryDate = 2020-02-01
@FinishDate = 2019-06-18
 
The job No: [002]
@JobDate = 2020-04-15
@CurrentDay = 56
@WorkDays = 56
@DeliveryDate = 2020-08-01
@FinishDate = 2020-06-10
 
The job No: [003]
@JobDate = 2020-05-05
@CurrentDay = 72
@WorkDays = 68
@DeliveryDate = 2020-06-01
@FinishDate = 2020-07-16
The job [003] will be finished after the Delivery Date:
Avatar of slightwv (䄆 Netminder)
slightwv (䄆 Netminder)

Personally I wouldn't use procedural code when you can meet requirements with straight SQL.



Avatar of Philippe Renaud

ASKER

Thank you guys, let me see all the answers, sorry for delay. i will come back

If you can post expected results with the sample data you posted, we can post tested SQL.

Scott I had some problems to understand your Cross apply with the select TOP
got some errors

I did test it.  Please let know the specific error(s) you are getting.  The syntax I used should be valid from SQL 2005 on.