SQL Query, bring data between 2 dates with limitation - sql

In SQL, I am going to write a query which insert all data between 2 dates and also I want to bring then in a 1000 batch but since the number of data between those days are more than my limitation I was going to write a loop which makes the smaller period to bring the data.
here is my code:
DECLARE #StartDate DATETIME = CAST('2021-06-02 01:00:00.000' AS DATETIME)
DECLARE #EndDate DATETIME = CAST('2021-06-23 01:00:00.000' AS DATETIME)
DECLARE #RealRowCount INT = (SELECT DISTINCT SUM(##ROWCOUNT) OVER() FROM GetReport (
#StartDate, #EndDate))
DECLARE #TransactionCount INT = (SELECT DISTINCT TransactionCount FROM GetReport (
#StartDate, #EndDate))
WHILE #RealRowCount < #TransactionCount
BEGIN
DECLARE #DiffDate INT = (SELECT DATEDIFF(DAY, #StartDate, #EndDate))
SET #EndDate = DATEADD(DAY, #DiffDate/2 ,#StartDate)
SELECT *,#StartDate, #EndDate FROM GetReport (#StartDate, #EndDate)
END
PS: I was thinking about find the middle of the period of date and then change them into the new EneDate and StartDate but there is problem here!

Your question is not very clear. Suppose you have 10,000 records between two dates and you do not want to retrieve more than a thousand records at a time. In this case, you can use pagination. Both in the program code and in SQL.
DECLARE #StartDate DATETIME = CAST('2021-06-02 01:00:00.000' AS DATETIME)
DECLARE #EndDate DATETIME = CAST('2021-06-23 01:00:00.000' AS DATETIME)
DECLARE #RealRowCount INT = (SELECT DISTINCT COUNT(*) FROM Products WHERE InsertDate BETWEEN #StartDate AND #EndDate)
DECLARE #Counter INT = 0
WHILE #Counter <= #RealRowCount
BEGIN
SELECT *
FROM Products
WHERE InsertDate BETWEEN #StartDate AND #EndDate
ORDER BY InsertDate
OFFSET #Counter ROWS -- skip #Counter rows
FETCH NEXT 1000 ROWS ONLY -- take 1000 rows
SET #Counter = #Counter + 1000
END
Or you can get the time difference between the two dates and add the start date each time in a specific step and retrieve the data of that date.
For example, the date difference is 20 days. Increase the start date by 5 steps each time to the start date with the end date

I create another table to put Dates and if this table has any rows I can get 'EndDate', but if it has not any records I simply just use the date that I specified.
AccSync is the table that I insert details of my records and AccTransformation is the table wich I want to insert all of my records.
DECLARE #Count INT = (SELECT COUNT(*) FROM [AccTransaction])
DECLARE #Flag BIT = (SELECT IIF(#Count > 1, 1, 0))
DECLARE #End DATETIME = GETDATE();
DECLARE #Start DATETIME
IF(#Flag = 0)
BEGIN
SET #Start = CAST('2021-03-08' AS DATETIME2);
SET #Flag = 1
END
ELSE IF(#Flag = 1)
BEGIN
SET #Start = (SELECT TOP 1 EndDate FROM (SELECT EndDate FROM [AccSync] ORDER BY ActionDate DESC OFFSET 0 ROW) AS TT);
END
DECLARE #RealRowCount INT = (SELECT DISTINCT SUM(##ROWCOUNT) FROM [GetReport] (#Start, #End));
DECLARE #TransactionCount INT = (SELECT DISTINCT TransactionCount FROM [GetReport] (#Start, #End));
----------------------------------------------------------------------------------------------
WHILE (#RealRowCount <> #TransactionCount)
BEGIN
DECLARE #DiffDate INT = (SELECT DATEDIFF(SECOND, #Start, #End))
SET #End = DATEADD(SECOND, (#DiffDate/2), #Start)
SET #RealRowCount = (SELECT DISTINCT SUM(##ROWCOUNT) FROM [GetReport] (#Start, #End))
SET #TransactionCount = (SELECT DISTINCT TransactionCount FROM [GetReport] (#Start, #End))
END
----------------------------------------------------------------------------------------------
INSERT INTO [AccTransaction]
SELECT *
FROM [GetReport](#Start, #End)
----------------------------------------------------------------------------------------------
INSERT INTO [AccSync]
VALUES(NEWID(), GETDATE(), #Start, #End, ISNULL(#TransactionCount,0), DATEDIFF(SECOND, #Start, #End))

Related

How to pass multiple values one by one for a Parameter in an SQL Query and union the results?

I have an SQL Statement which accepts a parameter #EndDate as DateTime. I want to be able to pass several values for #EndDate one by one and then Union the results of all the Queries. I have tried using CTE for this but it is of no use. I want to pass several Dates for #EndDate. Any help would be greatly appreciated.
My Query is:
DECLARE #EndDate as DateTime
SET #EndDate = '2018/02/25'
SELECT
CONVERT(VARCHAR, #EndDate, 101) [R_Date]
,[Name]
[Type]
FROM [dbo].[S_Table]
This is Sample query how u can loop through multiple dates. A while loop should select all rows into one table, do not need to perform union all
DECLARE #table TABLE (
day INT
,Month INT
,DATE DATE
)
DECLARE #startdate DATE = '2018/02/25'
DECLARE #enddate DATE = cast(getdate() AS DATE)
WHILE #startdate <= #enddate
BEGIN
SELECT #startdate = dateadd(dd, 1, #startdate)
INSERT #table (
day
,Month
,DATE
)
SELECT day(#startdate)
,MONTH(#startdate)
,#startdate
END
SELECT *
FROM #table;
In your logic for passing multiple values into query , you can store result set into temporal table, which holds looped records
DECLARE #table TABLE (
[R_Date] DATE
,Name VARCHAR(155)
,Value VARCHAR(155)
)
DECLARE #enddate DATE = '2018/02/25'
DECLARE #enddate1 DATE = cast(getdate() AS DATE)
WHILE #enddate <= #enddate1
BEGIN
SELECT #enddate = dateadd(dd, 1, #enddate)
INSERT #table (
R_Date
,Name
,Value
)
SELECT CONVERT(VARCHAR, #EndDate, 101) [R_Date]
,[Name] [Type]
FROM [dbo].[S_Table]
WHERE DATE = #enddate
-------More filters
END
SELECT *
FROM #table;

count the weekend and holiday dates and sub struct it from 2 dates if it is between of it sql

I have 3 tables with columns shown below,
Holidays : HolidayId, HolidayName, HolidayDate, Comment
Entitlements:
EntitlementId, EmployeeId, LeaveTypeId, LeavePeriodId, FromDate
, UptoDate, Entitlementdays
Weekend: WeekeindId, Weekends
TODO:
create a store procedure for insertion
Before insertion it should check and count the dates in holiday and weekend table
if it is between the date which is in the startdate and enddate of entitlement table should be subtract.
in sql
Try this one as you already have weekend table and holiday table
CREATE PROCEDURE
usp_LeaveDays (#employeeid int)
as
BEGIN
DECLARE #fromdate DATE
SET #fromdate =
SELECT convert( varchar(10),fromdate,120) fromdate
FROM Entitlement
WHERE employeeid = #employeeid
DECLARE #enddate DATE
SET #enddate =
SELECT convert ( varchar(10),enddate,120) enddate
FROM entitlement
WHERE employeeid = #employeeid
DECLARE #weekendcount INT
SET #weekendcount =
SELECT Count(*)
FROM Weekend
WHERE weekends BETWEEN #fromdate AND #enddate;
DECLARE #holidayCount INT
SET #holidaycount =
SELECT Count(*)
FROM holidays
WHERE holidaydate BETWEEN #fromdate AND #enddate
DECLARE #Totaldays INT
SET #Totaldays =
SELECT DATEDIFF(day, #fromdate, #enddate)
DECLARE #Actualdays INT
SET #Actualdays = #Totaldays - (#weekendcount + isnull(#holidayCount, 0))
DECLARE #recordCount INT
SELECT #recordCount = #Actualdays
IF (#recordCount > 0)
begin
insert into -- Enter your script here
END

How to add hours to work day in SQL?

I have seen many example adding working date (business days) to date in SQL. But I would like to add hour.
For example; I would like to add 36 hour to date not in Sunday , Saturday
Could one help me about it ?
CREATE FUNCTION AddWorkDays
(
#WorkingDays As Int,
#StartDate AS DateTime
)
RETURNS DateTime
AS
BEGIN
DECLARE #Count AS Int
DECLARE #i As Int
DECLARE #NewDate As DateTime
SET #Count = 0
SET #i = 0
WHILE (#i < #WorkingDays) --runs through the number of days to add
BEGIN
-- increments the count variable
SELECT #Count = #Count + 1
-- increments the i variable
SELECT #i = #i + 1
-- adds the count on to the StartDate and checks if this new date is a Saturday or Sunday
-- if it is a Saturday or Sunday it enters the nested while loop and increments the count variable
WHILE DATEPART(weekday,DATEADD(d, #Count, #StartDate)) IN (1,7)
BEGIN
SELECT #Count = #Count + 1
END
END
-- adds the eventual count on to the Start Date and returns the new date
SELECT #NewDate = DATEADD(d,#Count,#StartDate)
RETURN #NewDate
END
GO
The following will add N hours to a date (excluding Saturday and Sundays).
Example
Declare #Date1 datetime = '2017-04-28'
Declare #Hours int = 36
Select D=max(D)
From (
Select D,HN=-1+Row_Number() over (Order by D)
From (Select D=DateAdd(HOUR,-1+Row_Number() Over (Order By (select null)),#Date1) From master..spt_values n1 ) D
Where DateName(WEEKDAY,D) not in ('Saturday','Sunday')
) D1
Where HN=#Hours
Returns
2017-05-01 12:00:00.000
is it what you are looking for?
declare #num_hours int;
set #num_hours = 1;
select dateadd(HOUR, #num_hours, getdate()) as time_with_hour;
declare #num_hours int;
set #num_hours = 5;
select dateadd(HOUR, #num_hours, getdate()) as time_added,
getdate() as curr_date
This question is already answered Here

Looping distinct values from one table through another without a join

I know looping is not ideal in SQL, but I couldn't think of another way of doing this.
I want each distinct row from this Table 1 to have each distinct date and hour produced on Table 2.
In other words, Table 2 has the dates between 05/01/2014 through 04/30/2015, with each distinct date having 24 rows, one for each hour of the day. I now want each distinct row in Table 1 to have each distinct date on Table 2, with each of its 24 hours.
Table 1:
DROP TABLE Baylor_Raw..MEDICAL_SERVICE_DESC
SELECT MEDICAL_SERVICE_DESC
INTO Baylor_Raw..MEDICAL_SERVICE_DESC
FROM Baylor_Raw..Raw_ADT
WHERE MEDICAL_SERVICE_DESC IS NOT NULL AND MEDICAL_SERVICE_DESC NOT IN ('#N/A','CANCEL','DAY SURGERY','HOSPICE','INFUSION')
Table 2:
DECLARE #DATE DATE
SET #DATE = '05/01/2014'
DECLARE #HOUR INT
SET #HOUR = 0
DROP TABLE Baylor_Raw..DateTable
CREATE TABLE Baylor_Raw..DateTable
(DATE_OF_DISCHARGE DATE
,HOUR_OF_DISCHARGE INT)
WHILE #DATE<'05/01/2015' BEGIN
WHILE #HOUR<25 BEGIN
INSERT INTO Baylor_Raw..DateTable (DATE_OF_DISCHARGE,HOUR_OF_DISCHARGE)
VALUES (#DATE,#HOUR)
SET #HOUR = #HOUR+1
END
SET #DATE = DATEADD(DD,1,#DATE)
SET #HOUR = 0
END
This below attempt did not work. I canceled after the run time exceeded several minutes.
DECLARE #MEDICAL_SERVICE_DESC NVARCHAR(255)
SET #MEDICAL_SERVICE_DESC = (SELECT MIN(MEDICAL_SERVICE_DESC) FROM Baylor_Raw..MEDICAL_SERVICE_DESC)
DECLARE #DATE DATE
SET #DATE = '05/01/2014'
DECLARE #HOUR INT
SET #HOUR = 0
DROP TABLE Baylor_Raw..DateTable
CREATE TABLE Baylor_Raw..DateTable
(MEDICAL_SERVICE_DESC NVARCHAR,
DATE_OF_DISCHARGE DATE
,HOUR_OF_DISCHARGE INT)
WHILE #MEDICAL_SERVICE_DESC IS NOT NULL BEGIN
WHILE #DATE<'05/01/2015' BEGIN
WHILE #HOUR<25 BEGIN
INSERT INTO Baylor_Raw..DateTable (MEDICAL_SERVICE_DESC,DATE_OF_DISCHARGE,HOUR_OF_DISCHARGE)
VALUES (#MEDICAL_SERVICE_DESC,#DATE,#HOUR)
SET #HOUR = #HOUR+1
END
SET #DATE = DATEADD(DD,1,#DATE)
SET #HOUR = 0
END
DELETE FROM Baylor_Raw..MEDICAL_SERVICE_DESC WHERE MEDICAL_SERVICE_DESC = #MEDICAL_SERVICE_DESC
SET #MEDICAL_SERVICE_DESC = (SELECT MIN(MEDICAL_SERVICE_DESC) FROM Baylor_Raw..MEDICAL_SERVICE_DESC)
SET #DATE = '05/01/2014'
END
So you want all distinct records from table1 paired with all records in table2? That is a cross join:
select *
from (select distinct * from table1) t1
cross join table2;
Or do you want them related by date? Then inner-join:
select *
from (select distinct * from table1) t1
inner join table2 t2 on t1.date = t2.date;
You might get better performance from building lists of dates and hours using loops first, and then combining it with the service names just one time using a cross join, something like this. You may need to tweak it a bit because you understand the source data:
DECLARE #dates TABLE (DATE DATE)
DECLARE #hours TABLE (hours INT)
DECLARE #hour INT
,#date DATE
SET #hour = 0
SET #date = '05/01/2014'
WHILE (#hour < 25)
BEGIN
INSERT INTO #hours
SELECT #hour
SET #hour = #hour + 1
END
WHILE (# DATE < '05/01/2015')
BEGIN
INSERT INTO #dates
SELECT #date
SET #DATE = DATEADD(DD, 1, #DATE)
END
INSERT INTO Baylor_Raw..DateTable (
MEDICAL_SERVICE_DESC
,DATE_OF_DISCHARGE
,HOUR_OF_DISCHARGE
)
SELECT MEDICAL_SERVICE_DESC
,DATE
,hour
FROM Baylor_Raw..MEDICAL_SERVICE_DESC
CROSS JOIN #date d
CROSS JOIN #hours h

Displaying the number of valid results for a range of dates

I currently have a table with a creation date and a expiry date. I currently have a sql command to get the number of valid items for a given date.
select
count(id) ,CONVERT(date, getdate())
from
table
where
createDate < getdate() and expDate > getdate()
This returns the count and current date.
Is it possible to wrote a sql query that will return the result for a range of dates, say I if wanted to plot the number of valid items over a range of 15 days?
Thanks!
Try this:
create table #datelist (ValidDateCheck date, ValidResults int)
declare #startdate date = '1/1/2015'
declare #enddate date = '2/1/2015'
declare #interval int = 1 --Use 1 if you want every day between your dates, use 2 if you want every other day, etc.
declare #datecounter date = #startdate
declare #count int
while #datecounter <= #enddate
begin
set #count =
(select count(*)
from Table
where CrtDt <= #datecounter and ExpDt > #datecounter)
insert into #datelist values (#datecounter, #count)
set #datecounter = dateadd(dd, #interval, #datecounter)
end
select * from #datelist order by 1
It loops through all the dates in your range, counting valid results for each one.
Check this,
DECLARE #StartDate DATETIME,
#EndDate DATETIME;
SELECT #StartDate = '20110501'
,#EndDate = '20110801';
SELECT
DATEADD(d, x.number, #StartDate) AS MonthName1
,
x.number
FROM master.dbo.spt_values x
WHERE x.type = 'P'
AND x.number <= DATEDIFF(MONTH, #StartDate, #EndDate);
The above query give the list of dates between 2 dates.
As per your table and question, check this also.
declare #table table(id int,frdt datetime, todt datetime)
insert into #table values (1,GETDATE()-20, GETDATE()-19)
,(2,GETDATE()-9, GETDATE()-8)
,(3,GETDATE()+20, GETDATE()+18)
,(4,GETDATE(), GETDATE()-1)
,(5,GETDATE()-20, GETDATE())
,(6,GETDATE()-10, GETDATE()+10 )
select * from #table
declare #frdt datetime = null , #todt datetime = getdate()-10
select #frdt, #todt,* from #table
where
(#frdt is null or #frdt between frdt and todt)
and
(#todt is null or #todt between frdt and todt)
select #frdt = GETDATE()-15 , #todt = GETDATE()
select #frdt, #todt,* from #table
where
(#frdt is null or #frdt between frdt and todt)
and
(#todt is null or #todt between frdt and todt)