Searching date between two given Dates - sql-server

I have two specific dates.
lets say from 2014-04-04 To 2015-10-04.
I have a plan that says classes of Blah course will be on mon, wed and Fri.
Now I want to get the dates of each mon, wed and Fri from 2014-04-04 to 2015-10-04.

With a calendar table it is simple:
SELECT t.*
FROM dbo.TableName t
INNER JOIN CalendarTable c
ON t.DateColumn = c.Date
WHERE c.Date between '2014-04-04' AND '2015-10-04'
AND DATEPART(dw, c.Date) IN (1,3,5)
How to generate a calendar table (look for "Calendar table").

The standard reply to this by any seasoned SQL Server veteran, would be to create a calendar table. But all too often this is scoffed. So here's a slow and out-of-the-box method:
DECLARE #startDate DATE = '2014-04-04', #endDate DATE = '2015-10-04';
WITH CTE(N) AS (SELECT 1 FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1))a(N)),
CTE2(N) AS (SELECT 1 FROM CTE x CROSS JOIN CTE y),
CTE3(N) AS (SELECT 1 FROM CTE2 x CROSS JOIN CTE2 y),
CTE4(N) AS (SELECT 1 FROM CTE3 x CROSS JOIN CTE3 y),
CTE5(N) AS (SELECT 1 FROM CTE4 x CROSS JOIN CTE4 y),
CTE6(N) AS (SELECT 0 UNION ALL
SELECT TOP (DATEDIFF(day,#startDate,#endDate))
ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
FROM CTE5),
TALLY(N) AS (SELECT DATEADD(day, N, #startDate)
FROM CTE6
WHERE DATENAME(weekday,DATEADD(day, N, #startDate)) IN ('Monday','Tuesday','Wednesday'))
SELECT N
FROM TALLY
ORDER BY N;

You can use a Recursive CTE if you do not have numbers table. Something like this. Note that the DATEPART(weekday,Dates) IN(1,3,5) is based on your setting of SELECT ##DATEFIRST.
For example If ##DATEFIRST is 1 then use DATEPART(weekday,Dates) IN(1,3,5)
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate = '2014-04-04'
SET #EndDate = '2015-10-04'
;WITH CTE AS
(
SELECT #StartDate Dates
UNION ALL SELECT DATEADD(d,1,Dates) FROM CTE WHERE DATEADD(d,1,Dates) <=#EndDate
)
SELECT Dates,DATENAME(weekday,Dates) FROM CTE
WHERE DATEPART(weekday,Dates) IN(1,3,5)
OPTION (MAXRECURSION 0);
GO

DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate = '2014-04-04'
SET #EndDate = '2015-10-04'
;WITH CTE AS
(
SELECT #StartDate Dates
UNION ALL SELECT DATEADD(d,1,Dates) FROM CTE WHERE DATEADD(d,1,Dates) <=#EndDate
)
SELECT Dates,DATENAME(weekday,Dates) FROM CTE
WHERE DATEPART(weekday,Dates) IN(1,3,5)
OPTION (MAXRECURSION 0);
GO
--- thanks to #ughai

I've comeup with another way to do this.
this query will not only Show the dates in between but also it will compare the dates u want to compare with.
Q.Dates Comparison
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate = '2014-12-22'
SET #EndDate = '2015-02-13'
drop table #TabCourseDetailID
SELECT ROW_NUMBER() OVER(ORDER BY CourseDetailID asc) AS Row,
CourseDetailID
into #TabCourseDetailID
from coursedetail
where UnitType='T' and courseID =1
Declare #counter as int
Declare #CourseDetailID varchar(500)
set #counter = 0
Declare #TempTable Table (FirstValue datetime,LastValue int)
while #StartDate <= #EndDate
begin
If DATEPART(WeekDay,#StartDate) IN (2,4,6)
begin
Set #Counter = #counter+1
Select #CoursedetailId=CoursedetailId
from #TabCourseDetailID
where row=#counter
insert into #TempTable (FirstValue,LastValue)
values (#StartDate,#CoursedetailId)
end
set #StartDate =DATEADD(d,1,#StartDate)
end
select t.LastValue,
t.FirstValue,
bp.conductedDate
from batchprogress bp
Join #TempTable t on (t.LastValue=bp.CoursedetailID)
where CourseID =1 and batchID =5
order by t.lastvalue

Related

Get dates between 2 dates with equal intervals

I have 2 dates 01/04/2017 and 30/04/2017. I want all the dates between these 2 dates with 7 days interval.
Expected Output :
01/04/2017
08/04/2017
15/04/2017
22/04/2017
29/04/2017
Please help!!
DECLARE #StartDate DATETIME,
#EndDate DATETIME
SELECT #StartDate = '2017-04-01',
#EndDate = '2017-04-30'
SELECT DATEADD(DAY, number*7, #StartDate)
FROM master.dbo.spt_values
WHERE type='P'
AND #EndDate >= DATEADD(DAY, number*7, #StartDate)
One method would be to use a Calendar table. Then return the results from there using the modulus to get the 7th rows:
WITH Dates AS(
SELECT *,
ROW_NUMBER() OVER (ORDER BY [date]) AS RN
FROM DateTable
WHERE [Date] BETWEEN '20170401' AND '20170430')
SELECT *
FROM Dates
WHERE (RN - 1) % 7 = 0;
I've used this solution, as from your post you imply that you might supply any date range, and that the 1st day may not necessarily be a Monday (or other specific day).
Try this
DECLARE #STRT DATETIME='04/01/2017',#END DATETIME ='04/30/2017'
;WITH CTE
AS
(
SELECT
MyDate = CAST(#STRT AS DATETIME)
UNION ALL
SELECT
MyDate = CAST(MyDate AS DATETIME)+7
FROM CTE
WHERE CAST(MyDate AS DATETIME)+7 < CAST(#END AS DATETIME)
)
SELECT
*
FROM CTE
result
Declare #StartDate DATE=CONVERT(DATE,'01/04/2017',104),#EndDate DATE=CONVERT(DATE,'01/12/2017',104)
Declare #String NVARCHAR(MAX)=''
WHILE (#StartDate<=#EndDate AND DATEDIFF(wk,#StartDate,#EndDate)>=0)
BEGIN
SET #String=#String+CONVERT(NVARCHAR(100),#StartDate)+CHAR(10)+CHAR(13)
SET #StartDate=DATEADD(d,7,#StartDate)
END
PRINT #String
GO

Group by Datepart using total month daywise total orders

here this is my stored procedure.. per day how many new orders and oldo rders are there in overall month..
i was declare date,totalorders and revenue..
result i'm getting only last day of the month that is 31st.. i want daywise orders count..
alter Procedure sp_NewandOld
(
#StartDate DATETIME,
#EndDate DATETIME
)
--[sp_NewandOld] '01/01/2015','01/31/2015'
AS
BEGIN
---New Customer Orders Breakup
Declare #NewCount int, #NewRevenue int, #NewDate nvarchar(50)
select #NewDate=(datepart(day,od.OrderDate)),
#NewCount= count(*),
#NewRevenue= SUM(CONVERT(decimal(18,2),od.TotalAmount)) from orderdetails od
inner join customer c on od.customerid=c.customerid
where Convert(Datetime,Convert(varchar(50),od.orderdate,101)) = Convert(Datetime,Convert(varchar(50),c.registereddate,101))
and Convert(Datetime,convert(varchar(50),od.orderdate,101)) between #StartDate and #EndDate
group by datepart(day, od.OrderDate)
Declare #OldCount int, #OldRevenue int, #OldDate nvarchar(50)
select #OldDate=(datepart(day,od.OrderDate)),
#OldCount= count(*),
#OldRevenue=SUM(CONVERT(decimal(18,2),od.TotalAmount)) from orderdetails od
inner join customer c on od.customerid=c.customerid
where Convert(Datetime,Convert(varchar(50),od.orderdate,101)) != Convert(Datetime,Convert(varchar(50),c.registereddate,101))
and Convert(Datetime,convert(varchar(50),od.orderdate,101)) between #StartDate and #EndDate
group by datepart(day, od.OrderDate)
select #NewDate,#NewCount,#OldCount,#NewRevenue,#OldRevenue
End
You select only first-row-values into a variables, and you need to get all. Change your query to this to get all data:
alter Procedure sp_NewandOld (
#StartDate DATETIME,
#EndDate DATETIME
)
AS
BEGIN
with [new] as (
select datepart(month,od.OrderDate) as newdatemonth,
datepart(day,od.OrderDate) as newdate,
count(*) as NewCount,
SUM(CONVERT(decimal(18,2),od.TotalAmount)) as NewRevenue
from orderdetails od
inner join customer c
on od.customerid=c.customerid
where Convert(Datetime,Convert(varchar(50),od.orderdate,101)) = Convert(Datetime,Convert(varchar(50),c.registereddate,101))
and Convert(Datetime,convert(varchar(50),od.orderdate,101)) between #StartDate and #EndDate
group by datepart(month,od.OrderDate), datepart(day, od.OrderDate)
), [old] as (
select datepart(month,od.OrderDate) as OldDateMonth,
datepart(day,od.OrderDate) as OldDate,
count(*) as OldCount,
SUM(CONVERT(decimal(18,2),od.TotalAmount)) as OldRevenue
from orderdetails od
inner join customer c
on od.customerid=c.customerid
where Convert(Datetime,Convert(varchar(50),od.orderdate,101)) != Convert(Datetime,Convert(varchar(50),c.registereddate,101))
and Convert(Datetime,convert(varchar(50),od.orderdate,101)) between #StartDate and #EndDate
group by datepart(month,od.OrderDate) , datepart(day, od.OrderDate)
)
select n.newdatemonth,
n.NewDate,
n.NewCount,
o.OldCount,
n.NewRevenue,
o.OldRevenue
from [new] n
inner join [old] o
on n.newdate = o.olddate and n.newdatemonth = o.OldDateMonth
End

Sequence of dates starting since 2015-01-01 until today

I want to produce sequence of dates since given date until today using one select command. It is possible?
WITH DATES_CTE AS (
SELECT TOP 100000
ROW_NUMBER() OVER (ORDER BY a.object_id) - 1 AS DayNumber
FROM
sys.all_columns a
CROSS JOIN
sys.all_columns b)
SELECT
DATEADD(DAY, DayNumber, 0) AS DateValue
FROM
DATES_CTE
WHERE
DATEADD(DAY, DayNumber, 0) >= '2016-01-01'
AND DATEADD(DAY, DayNumber, 0) < '2016-05-01';
Try this with CTE.
WITH CTE_DATE
AS
( SELECT CONVERT(DATE,'2015-01-01') AS CDATE
UNION ALL
SELECT DATEADD(DAY,1,CDATE)
FROM CTE_DATE
WHERE DATEADD(DAY,1,CDATE) <= GETDATE()
)
SELECT * FROM CTE_DATE
option (maxrecursion 0) -- for unlimited recursion
You can use the option option (maxrecursion 0) to avoid the limit recursion.
CREATE TABLE #date (datevalues date)
DECLARE #mindate DATE = '2015-01-01',
#maxdate DATE = GETDATE()
WHILE #mindate <= #maxdate
BEGIN
INSERT INTO
#date (datevalues)
SELECT #mindate
SELECT #mindate = dateadd(dd,1,#mindate)
END
GO
SELECT *FROM #date
GO
DROP TABLE #date
GO

SQL Server : multiple join query optimization

I've just started with Microsoft SQL Server and I'm facing a problem, which I believe it is an sql optimization issue. Could you please take a look (see below) and give me your feedback.
I have two tables defined as follows:
floatTable (DateAndTime datetime2(7),
TagIndex smallint,
Val float)
stringTable (DateAndTime datetime2(7),
TagIndex smallint,
Val float)
The SQL query which I have used to get the RESULT is (don't laugh):
DECLARE #startDate DATETIME, #endDate DATETIME
SET #startDate = '20130312 9:00:00'
SET #endDate = '20130313 9:00:00'
USE TensionDB
SELECT t1.DateAndTime, t1.Val AS Winch_1,t2.Val AS Winch_2, t3.Val AS Winch_3, t4.Val AS Winch_4, t5.Val AS Winch_5,
t6.Val AS Winch_6, t7.Val AS Winch_7, t8.Val AS Winch_8, t9.Val AS Latitude, t10.Val AS Longitude
FROM
((SELECT DISTINCT DateAndTime ,Val FROM dbo.FloatTable
WHERE (DateAndTime BETWEEN #startDate AND #endDate) AND TagIndex = 0)t1
INNER JOIN (SELECT DISTINCT DateAndTime,Val FROM dbo.FloatTable
WHERE ( DateAndTime BETWEEN #startDate AND #endDate) AND TagIndex = 1)t2
ON t2.DateAndTime = t1.DateAndTime
INNER JOIN (SELECT DISTINCT DateAndTime,Val FROM dbo.FloatTable
WHERE (DateAndTime BETWEEN #startDate AND #endDate) AND TagIndex = 2)t3
ON t3.DateAndTime = t1.DateAndTime
INNER JOIN (SELECT DISTINCT DateAndTime,Val FROM dbo.FloatTable
WHERE (DateAndTime BETWEEN #startDate AND #endDate) AND TagIndex = 3)t4
ON t4.DateAndTime = t1.DateAndTime
INNER JOIN (SELECT DISTINCT DateAndTime,Val FROM dbo.FloatTable
WHERE (DateAndTime BETWEEN #startDate AND #endDate) AND TagIndex = 4)t5
ON t5.DateAndTime = t1.DateAndTime
INNER JOIN (SELECT DISTINCT DateAndTime,Val FROM dbo.FloatTable
WHERE (DateAndTime BETWEEN #startDate AND #endDate) AND TagIndex = 5)t6
ON t6.DateAndTime = t1.DateAndTime
INNER JOIN (SELECT DISTINCT DateAndTime,Val FROM dbo.FloatTable
WHERE (DateAndTime BETWEEN #startDate AND #endDate) AND TagIndex = 6)t7
ON t7.DateAndTime = t1.DateAndTime
INNER JOIN (SELECT DISTINCT DateAndTime,Val FROM dbo.FloatTable
WHERE (DateAndTime BETWEEN #startDate AND #endDate) AND TagIndex = 7)t8
ON t8.DateAndTime = t1.DateAndTime
INNER JOIN (SELECT DISTINCT DateAndTime, Val FROM dbo.StringTable
WHERE (DateAndTime BETWEEN #startDate AND #endDate) AND TagIndex = 8)t9
ON t9.DateAndTime = t1.DateAndTime
INNER JOIN (SELECT DISTINCT DateAndTime, Val FROM dbo.StringTable
WHERE (DateAndTime BETWEEN #startDate AND #endDate) AND TagIndex = 9)t10
ON t10.DateAndTime = t1.DateAndTime)
PROBLEM: The big problem is that even if I get the correct result, the query gets very slow for large amount of data. I'm pretty sure that there is another way to write the query, but for the moment I don't have any other idea.
Could you give me a hint please? Appreciate any help from your side.
Thank you in advance
#Kiril and #Patrick,
Using your hints and ideas I have re-wrote my original query using pivot table.
Unfortunately, I still have to use INNER JOIN, as the values(Val) in the stringTable are strings and values(Val) in floatTable are floats. To be honest, I have to perform more tests with both queries, as I can't see a real improvement (time wise), using pivot table; apart from the length of the query. One last thing, I have embedded the query in a stored procedure. Please find below the "final" code:
-- ================================================
-- Template generated from Template Explorer using:
-- Create Procedure (New Menu).SQL
--
-- Use the Specify Values for Template Parameters
-- command (Ctrl-Shift-M) to fill in the parameter
-- values below.
--
-- This block of comments will not be included in
-- the definition of the procedure.
-- ================================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: xxxx
-- Create date: xxxx
-- Description: retrieves tension data
-- =============================================
CREATE PROCEDURE getTension
-- Add the parameters for the stored procedure here
#startDate datetime = NULL,
#endDate datetime = NULL
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT distinct pvt.DateAndTime
, pvt.[0] AS Winch_1
, pvt.[1] AS Winch_2
, pvt.[2] AS Winch_3
, pvt.[3] AS Winch_4
, pvt.[4] AS Winch_5
, pvt.[5] AS Winch_6
, pvt.[6] AS Winch_7
, pvt.[7] AS Winch_8
, st.Val AS Longitude
, st1.Val AS Latitude
FROM FloatTable
PIVOT
(MAX(Val)
FOR TagIndex in ([0],[1],[2],[3],[4],[5],[6],[7])
) as pvt
inner join StringTable st on st.DateAndTime = pvt.DateAndTime and st.TagIndex = 8
inner join StringTable st1 on st1.DateAndTime = pvt.DateAndTime and st1.TagIndex = 9
Where (pvt.DateAndTime between #startDate and #endDate)
ORDER BY DateAndTime
END
GO
Thanks again for your guidance
I suppose that using pivot table is going to be more efficient:
DECLARE #startDate DATETIME, #endDate DATETIME
SET #startDate = '20130312 9:00:00'
SET #endDate = '20130313 9:00:00'
SELECT st.DateAndTime
, pvt.0 AS Winch_1
, pvt.1 AS Winch_2
, pvt.2 AS Winch_3
, pvt.3 AS Winch_4
, pvt.4 AS Winch_5
, pvt.5 AS Winch_6
, pvt.6 AS Winch_7
, pvt.7 AS Winch_8
, pvt.8 AS Latitude
, pvt.9 AS Longitude
FROM StringTable st
INNER JOIN FloatTable ft on st.DateandTime=ft.DateandTime
pivot
( MAX(Val) for [TagIndex] in ([0], [1], [2], [3], [4], [5], [6], [7], [8], [9])
order by [st.DateAndTime]
)pvt
I haven't tested it so you may have to tweak it a bit, in order to make it work.
Start putting DateAndTime and TagIndex in an index. That would make a difference.
On the other hand, your query could get a lot faster if you wouldn't need the repeating inner joins.
Can you replace the distinct by a single group by and use min or max?
Another option is using pivot tables.
Like this:
select *
from FloatTable
pivot (min(DateAndTime) x, min(Val) y in ([1],[2],[3], ...))

Update Statements in Stored Procedure Suquentially?

Below UPDATE A iam updating facot Sqares table
-iam using updatd factor from the sqare table to calulate final value in Parameter
Below UPDATE A iam updating facot Sqares table
Below UPDATE A iam updating facot Sqares table
DECLARE #Year char(8) = '2017';
WITH E1 AS(
SELECT N FROM (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) E(N)
),
E3 AS(
SELECT a.N FROM E1 a, E1 b, E1 c
),
cteTally AS(
SELECT TOP (360) DATEADD( dd, (ROW_NUMBER() OVER( ORDER BY (SELECT NULL)) - 1), CAST(#Year AS date)) myDate
FROM E3
),
weekDays AS(
SELECT myDate, ROW_NUMBER() OVER(PARTITION BY MONTH(myDate) ORDER BY myDate) rn
FROM cteTally
WHERE DATENAME( WEEKDAY, myDate) NOT IN ('Saturday', 'Sunday')
),
Final as(
SELECT
myDate StartDay,
datename(dw,myDate) Name,
DATEADD(dd,19,myDate) EndDay,
DATEADD(MM, DATEDIFF(MM, 0, myDate), 0) FirstDay
FROM weekDays
WHERE rn = 1
)
SELECT FirstDay,StartDay,Name as StartName,
case when Name='Monday' THEN DATEADD(dd,18,StartDay)
when Name='Tuesday' THEN DATEADD(dd,17,StartDay)
when Name='Wednesday' THEN DATEADD(dd,16,StartDay)
when Name='Thursday' THEN DATEADD(dd,15,StartDay)
when Name='Friday' THEN DATEADD(dd,14,StartDay)
ELSE NULL END AS EndDate,
case when Name='Monday' THEN datename(dw,DATEADD(dd,18,StartDay))
when Name='Tuesday' THEN datename(dw,DATEADD(dd,17,StartDay))
when Name='Wednesday' THEN datename(dw,DATEADD(dd,16,StartDay))
when Name='Thursday' THEN datename(dw,DATEADD(dd,15,StartDay))
when Name='Friday' THEN datename(dw,DATEADD(dd,14,StartDay))
ELSE NULL END AS EndName
into #Dates FROM Final
Declare a parameter #factor.
Alter the first statement to set #factor =select B.candy/b.randy ..... .
Then make the updates without the joins. (Use #factor)
Debug and analyze #factor to select your work.
Alternatively you could use (nolock) in the second update but please keep in mind that you did not commit your transaction as it looks right after the last update (your "problem" looks like you are in an transaction and your first update will not be commited before the second update so you select the table again which doesn't have your update yet)
This might occur due to datatype conversion.
please check the c. finalvalue could hold/insert/retrieve the return type of (cost*factor).
Sql server update will do its part perfect, but the datatype needs to be verified.
DECLARE #StartDate date
DECLARE #EndDate date
DECLARE #Cursor CURSOR
SET #Cursor = CURSOR FOR
select StartDay,EndDate from #Dates
OPEN #Cursor
FETCH NEXT
FROM #Cursor INTO #StartDate,#EndDate
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO #Dest
select #StartDate StartDate,#EndDate EndDate, Max(high) High,min(low) Low from #Results
where date between #StartDate and #EndDate
FETCH NEXT
FROM #Cursor INTO #StartDate,#EndDate
END
CLOSE #Cursor
DEALLOCATE #Cursor
SELECT B.[open],a.* FROM #Dest A
JOIN #Results B ON A.StartDate=B.dATE

Resources