I am trying to get order counts for everyday this year in 3pm to 3pm intervals
Select cast(order_datetime as date) ,count(*)
from order_table
where order_datetime> '01/01/2015 15:00'
group by ?????
I normally group by
cast(order_datetime as date) ---for 12am to 12am
but I want 3pm to 3pm.
This might be solution looking for i have taken a sample data and a table variable #t to solve it col1 in the table refers to Your problem
SET DATEFORMAT DMY
DECLARE #t TABLE
(
Id int,
Name varchar(11),
[Col1] DateTime
)
INSERT INTO #t
VALUES(1,'ABC','22/12/2012 03:45:00 PM'),(2,'SD','22/12/2012 03:01:00 PM'),(3,'SDSA','22/12/2012 02:01:00 PM'),(4,'ASDF','22/12/2012 03:30:00 PM'),(5,'ASWER','22/12/2012 02:30:00 PM')
,(11,'NARI','21/12/2012 03:40:00 PM')
SELECT CASE WHEN CAST(COL1 AS TIME) >'15:00:00' THEN CAST(DATEADD(DAY,1,Col1) AS date) ELSE CAST(Col1 AS DATE) END AS ORDERS,COUNT(*) AS COUNT
FROM #t
GROUP BY CASE WHEN CAST(COL1 AS TIME) >'15:00:00' THEN CAST(DATEADD(DAY,1,Col1) AS date) ELSE CAST(Col1 AS DATE) END
Related
In the table below, how to insert rows with the first and last date of years between the START_DATE and END_DATE column?
EMPID
EMPNAME
START_DATE
END_DATE
1001
Shivansh
2015-09-01
2018-03-31
1004
Mayank
2019-04-01
2020-06-30
The output should look as follows:
EMPID
EMPNAME
START_DATE
END_DATE
1001
Shivansh
2015-09-01
2015-12-31
1001
Shivansh
2016-01-01
2016-12-31
1001
Shivansh
2017-01-01
2017-12-31
1001
Shivansh
2018-01-01
2018-03-31
1004
Mayank
2019-04-01
2019-12-31
1004
Mayank
2020-01-01
2020-06-30
This has to be implemented using loops as Azure Synapse Analytics doesn't support Recursive common table expressions
This approach uses a numbers table and a number of date functions which are available in Azure Synapse Analytics dedicated SQL pools, including DATEFROMPARTS, DATEDIFF and YEAR.
NB This is not a recursive query. There is a loop used in the creation of the numbers table but this is done only once. Once the numbers table exists it can be used for similar scenarios, eg converting recursive CTEs to set-based approaches compatible with Azure Synapse Analytics.
DATEFROMPARTS is used to construct the first day of the year in the calculated records. I then use DATEADD to add one year, then take away one day, to get the last day of the year. DATEDIFF with year is used to determine the gap in years between the two dates and therefore the number of records that need to be added. I then UNION the original and calculated records for the full result.
IF OBJECT_ID('tempdb..#tmp') IS NOT NULL
DROP TABLE #tmp
GO
CREATE TABLE #tmp (
empId INT NOT NULL,
empName VARCHAR(50) NOT NULL,
start_date DATE NOT NULL,
end_date DATE NULL
)
GO
-- Setup test data
INSERT INTO #tmp ( empId, empName, start_date, end_date )
SELECT 1001, 'Shivansh', '2015-09-01', '2018-03-31'
UNION ALL
SELECT 1004, 'Mayank', '2019-04-01', '2020-06-30'
GO
;WITH cte AS (
SELECT *,
DATEFROMPARTS( YEAR(start_date) + n.number, 1, 1 ) newStart
FROM #tmp t
CROSS JOIN dbo.numbers n
WHERE n.number <= DATEDIFF( year, start_date, end_date )
)
SELECT 'o' s, empId, empName, start_date,
CASE
WHEN YEAR(start_date) = YEAR(end_date) THEN end_date
ELSE DATEFROMPARTS( YEAR(start_date), 12, 13 )
END end_date
FROM #tmp
UNION ALL
SELECT 'c', empId, empName,
newStart AS start_date,
CASE
WHEN YEAR(end_date) = YEAR(newStart) THEN end_date
ELSE DATEADD( day, -1, DATEADD( year, 1, newStart ) )
END newEnd
FROM cte
ORDER BY empId, start_date
My results:
I've added the o and c to indicate original and calculated rows but you can remove that column if you like. If you do not have a numbers table already then the script I used to create this one is here. This code has been tested on an Azure Synapse Analytics dedicated SQL pool, version Microsoft Azure SQL Data Warehouse - 10.0.15554.0 Dec 10 2020 03:11:10.
I found the workaround using a loop. The steps followed are as follows:
Create a temporary table to hold initial values.
CREATE TABLE #EMP
(
EMPID VARCHAR(10),
EMPNAME VARCHAR(10),
START_DATE DATE,
END_DATE DATE
);
Insert initial values.
INSERT INTO #EMP
SELECT '1001', 'Shivansh', '2015-09-01', '2018-03-31';
INSERT INTO #EMP
SELECT '1004', 'Mayank', '2019-04-01', '2020-06-30';
Create the required table.
CREATE TABLE #NEWEMP
(
EMPID VARCHAR(10),
EMPNAME VARCHAR(10),
START_DATE DATE,
END_DATE DATE
);
Insert the first year date (i.e. if the START_DATE for a tuple is 2015-09-01 insert 2015-09-01 for START_DATE and 2015-12-31 for the END_DATE).
INSERT INTO #NEWEMP
SELECT EMPID, EMPNAME, START_DATE, DATEFROMPARTS(YEAR(START_DATE), 12, 31) FROM #EMP;
Similarly, Insert the last year date.
INSERT INTO #NEWEMP
SELECT EMPID, EMPNAME, DATEFROMPARTS(YEAR(END_DATE), 1, 1), END_DATE FROM #EMP;
Run a while loop till the maximum value of the difference between START_DATE and END_DATE column.
DECLARE #counter INT = 1;
DECLARE #len INT = (SELECT MAX(DATEDIFF(YEAR, START_DATE, END_DATE)) FROM #EMP);
WHILE #counter < #len
BEGIN
INSERT INTO #NEWEMP
SELECT EMPID, EMPNAME, DATEFROMPARTS(YEAR(START_DATE) + #counter, 1, 1), DATEFROMPARTS(YEAR(START_DATE) + #counter, 12, 31) FROM #EMP
WHERE #counter < DATEDIFF(YEAR, START_DATE, END_DATE);
SET #counter += 1;
END
Query the output.
SELECT * FROM #NEWEMP ORDER BY START_DATE;
Here is the Query, written in Azure Synapse Analytics.
The required output is.
I have a table with multiple record against userid and datetime fields. A user have availability for same date everyhour.
UserId DateTime
1 2018-08-13 08:30:00 +05:30
1 2018-08-13 09:30:00 +05:30
1 2018-08-13 10:30:00 +05:30
1 2018-08-13 15:00:00 +05:30
1 2018-08-13 17:00:00 +05:30
1 2018-08-13 18:00:00 +05:30
Now If I search for date suppose 2018-08-13 11:30:00 +05:30
then I want in
Previous slot = 2018-08-13 **10:30:00** +05:30
and next slot = 2018-08-13 **15:00:00** +05:30
Update
Quick update I need smaller time for the same date not the previous day. Ex. For
2018-08-13 08:30:00 +05:30 it should show null as no small time available.
One more try with CTEs, edited to match the changed question:
DECLARE #SearchDate datetime = '2018-08-13 11:30:00',
#StartDate datetime,
#EndDate datetime,
#UserId int = 1;
SET #StartDate = DATETIMEFROMPARTS(YEAR(#SearchDate), MONTH(#SearchDate), DAY(#SearchDate), 0, 0, 0, 0);
SET #EndDate = DATEADD(day, 1, #StartDate);
WITH
ctePrevious AS
(
SELECT MAX([DateTime]) AS [DateTime]
FROM YourTable
WHERE UserId = #UserId AND [DateTime] BETWEEN #StartDate AND #SearchDate
),
cteNext AS
(
SELECT MIN([DateTime]) AS [DateTime]
FROM YourTable
WHERE UserId = #UserId AND [DateTime] BETWEEN #SearchDate AND #EndDate
)
SELECT ctePrevious.[DateTime] AS prevDate, cteNext.[DateTime] AS nextDate
FROM ctePrevious, cteNext
It should return NULL values if no entry is found for the given date.
You could add a rownumber and a self join. The following example will demonstrate how it works:
CREATE TABLE #T (ID INT, DateT DATETIME)
INSERT INTO #T VALUES (1, GETDATE() - .2)
INSERT INTO #T VALUES (1, GETDATE() - .1)
INSERT INTO #T VALUES (1, GETDATE() - .05)
INSERT INTO #T VALUES (1, GETDATE())
INSERT INTO #T VALUES (1, GETDATE() + .1);
WITH CTE AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RowNumb
FROM #T AS T
)
SELECT C.ID, C.DateT AS StartDate, C2.DateT AS EndDate
FROM CTE AS C
LEFT JOIN CTE AS C2 ON C.RowNumb = C2.RowNumb - 1
WHERE GETDATE() BETWEEN C.DateT AND C2.DateT -- your date input here
Make use of LEAD and LAG. This is Pseudo SQL, however:
SELECT DateColumn,
LAG(DateColumn) OVER (ORDER BY DateColumn) AS Previousslot,
LEAD(DateColumn) OVER (ORDER BY DateColumn) AS NextSlot
FROM YourTable;
This, unlike SQL_M's answer, means you don't need to do 2/3 scans of the table.
declare #wantedDate datetime = '2018-09-04 12:27:16.570'
select top 1 * from #t tP -- Top of each min and max time
join #T tn
on tp.ID = tn.ID
and tp.DateT <= #wantedDate -- all previous times
and tn.DateT >= #wantedDate -- all next times
order by tp.ID, tp.DateT desc, tn.DateT
Revert me, if query needs updates.
Given a table with a single row for each day of the month, how can I query it to get the row for the last day of each month?
Try adapting the following query. The SELECT statement within the IN clause choses the dates for the outer query to return.
SELECT *
FROM myTable
WHERE DateColumn IN
(
SELECT MAX(DateColumn)
FROM myTable
GROUP BY YEAR(Datecolumn), MONTH(DateColumn)
)
Try to make use of below query:
DECLARE #Dates Table (ID INT, dt DATE)
INSERT INTO #Dates VALUES
(1,'2017-02-01'),
(2,'2017-02-03'),
(3,'2017-02-04'),
(4,'2017-03-03'),
(5,'2017-04-03'),
(6,'2017-04-04')
SELECT MAX(dt) AS LastDay FROM #Dates GROUP BY DATEPART(MONTH,dt)
OUTPUT
LastDay
2017-02-04
2017-03-03
2017-04-04
OR
SELECT DATEPART(MONTH,dt) AS [MONTH],MAX(DATEPART(DAY,dt)) AS LastDay FROM #Dates GROUP BY DATEPART(MONTH,dt)
MONTH LastDay
2 4
3 3
4 4
You need to select from your table where the YourDateColumn field of the record equals the last date of the month YourDateColumn belongs to:
SELECT CAST(DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0, YourDateColumn )+1,0)) AS DATE)
Lets say I have following query:
SELECT top (5) CAST(Created AS DATE) as DateField,
Count(id) as Counted
FROM Table
GROUP BY CAST(Created AS DATE)
order by DateField desc
Lets say it will return following data set
DateField Counted
2016-01-18 34
2016-01-17 99
2016-01-14 1
2015-12-28 1
2015-12-27 6
But when I have Counted = 0 for certain Date I would like to get that in result set. So for example it should look like following
DateField Counted
2016-01-18 34
2016-01-17 99
2016-01-16 0
2016-01-15 0
2016-01-14 1
Thank you!
Expanding upon KM's answer, you need a date table which is like a numbers table.
There are many examples on the web but here's a simple one.
CREATE TABLE DateList (
DateValue DATE,
CONSTRAINT PK_DateList PRIMARY KEY CLUSTERED (DateValue)
)
GO
-- Insert dates from 01/01/2015 and 12/31/2015
DECLARE #StartDate DATE = '01/01/2015'
DECLARE #EndDatePlus1 DATE = '01/01/2016'
DECLARE #CurrentDate DATE = #StartDate
WHILE #EndDatePlus1 > #CurrentDate
BEGIN
INSERT INTO DateList VALUES (#CurrentDate)
SET #CurrentDate = DATEADD(dd,1,#CurrentDate)
END
Now you have a table
then you can rewrite your query as follows:
SELECT top (5) DateValue, isnull(Count(id),0) as Counted
FROM DateList
LEFT OUTER JOIN Table
on DateValue = CAST(Created AS DATE)
GROUP BY DateValue
order by DateValue desc
Two notes:
You'll need a where clause to specify your range.
A join on a cast isn't ideal. The type in your date table should match the type in your regular table.
One more solution as a single query:
;WITH dates AS
(
SELECT CAST(DATEADD(DAY, ROW_NUMBER() OVER (ORDER BY [object_id]) - 1, '2016-01-14') as date) 'date'
FROM sys.all_objects
)
SELECT TOP 5
[date] AS 'DateField',
SUM(CASE WHEN Created IS NULL THEN 0 ELSE 1 END) AS 'Counted'
FROM dates
LEFT JOIN Table ON [date]=CAST(Created as date)
GROUP BY [date]
ORDER BY [date]
For a more edgy solution, you could use a recursive common table expression to create the date list. PLEASE NOTE: do not use recursive common table expressions in your day job! They are dangerous because it is easy to create one that never terminates.
DECLARE #StartDate date = '1/1/2016';
DECLARE #EndDate date = '1/15/2016';
WITH DateList(DateValue)
AS
(
SELECT DATEADD(DAY, 1, #StartDate)
UNION ALL
SELECT DATEADD(DAY, 1, DateValue)
FROM DateList
WHERE DateList.DateValue < #EndDate
)
SELECT DateValue, isnull(Count(id),0) as Counted
FROM DateList
LEFT OUTER JOIN [Table]
ON DateValue = CAST(Created AS DATE)
GROUP BY DateValue
ORDER BY DateValue DESC
Is there a way to get the number of Mondays in a given month (and year) without using T-SQL?
Thanks
I'm not sure what you mean by saying:
Is there a way to get the number of Mondays in a given month (and
year) without using T-SQL?
If you are hoping for a universal code fragment that will do this across all databases, forget it. I doubt that you'll even be able to get a version to run on two different databases. Dates and things like weekdays tend to be be implemented differently across database vendors.
Here is the TSQL way (Monday Month Count):
;with AllDates AS
(SELECT CONVERT(datetime,CONVERT(varchar(6),GETDATE(),112)+'01') AS DateOf
UNION ALL
SELECT DateOf+1
FROM AllDates
WHERE
MONTH(DateOf+1)=MONTH(CONVERT(datetime,CONVERT(varchar(6),GETDATE(),112)+'01'))
)
SELECT COUNT(DateOf) AS MondayCountMonth
FROM AllDates
WHERE DATENAME(weekday,DateOf)='Monday'
Here is the TSQL way (Monday Year Count):
;with AllDates AS
(SELECT CONVERT(datetime,CONVERT(varchar(4),GETDATE(),112)+'0101') AS DateOf
UNION ALL
SELECT DateOf+1
FROM AllDates
WHERE
YEAR(DateOf+1)=Year(CONVERT(datetime,CONVERT(varchar(4),GETDATE(),112)+'0101'))
)
SELECT COUNT(DateOf) AS MondayCountYear
FROM AllDates
WHERE DATENAME(weekday,DateOf)='Monday'
OPTION (MAXRECURSION 367)
EDIT based on OP comment, here is a version which finds the monthly and yearly Monday counts as sub-queries within another query:
DECLARE #YourTable table (Col1 int, Col2 varchar(5))
INSERT #YourTable VALUES (1,'aaa')
INSERT #YourTable VALUES (2,'bbb')
INSERT #YourTable VALUES (3,'ccc')
;with MonthMondayCount AS
(SELECT CONVERT(datetime,CONVERT(varchar(6),GETDATE(),112)+'01') AS DateOf
UNION ALL
SELECT DateOf+1
FROM MonthMondayCount
WHERE
MONTH(DateOf+1)=MONTH(CONVERT(datetime,CONVERT(varchar(6),GETDATE(),112)+'01'))
)
,YearMondayCount AS
(SELECT CONVERT(datetime,CONVERT(varchar(4),GETDATE(),112)+'0101') AS DateOf
UNION ALL
SELECT DateOf+1
FROM YearMondayCount
WHERE
YEAR(DateOf+1)=Year(CONVERT(datetime,CONVERT(varchar(4),GETDATE(),112)+'0101'))
)
SELECT
y.*
,(SELECT COUNT(DateOf) AS MondayCountMonth FROM MonthMondayCount WHERE DATENAME(weekday,DateOf)='Monday') AS MondayCountMonth
,(SELECT COUNT(DateOf) AS MondayCountYear FROM YearMondayCount WHERE DATENAME(weekday,DateOf)='Monday') AS MondayCountYear
FROM #YourTable y
OPTION (MAXRECURSION 367)
OUTPUT:
Col1 Col2 MondayCountMonth MondayCountYear
----------- ----- ---------------- ---------------
1 aaa 5 52
2 bbb 5 52
3 ccc 5 52
(3 row(s) affected)
Try this : )
DECLARE #tmpDate as date
set #tmpDate = getdate(); --you can add any date
DECLARE #Startdate as varchar( 8)
DECLARE #Enddate as varchar( 8)
SELECT #Startdate = replace(convert(varchar,cast(DATEADD(month, DATEDIFF(month, 0, #tmpDate), 0) as date) , 111), '/', '');
SELECT #Enddate = replace(convert(varchar, cast(DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,#tmpDate)+1,0)) as date), 111), '/', '');
with [dates] as (
select convert(date , #Startdate ) as [date] --start
union all
select dateadd(day , 1 , [date])
from [dates]
where [date] < #Enddate )
Select X.WeekDayNumber, count(X.WeekDayNumber) as NumberOfDays
from (
SELECT [date] , DATEPART(weekday,[date] ) as WeekDayNumber
from [dates]
WHERE [date] IS NOT NULL)X
Group by X.WeekDayNumber
option (maxrecursion 0 )
( DATEADD( DAY, -1, DATEADD( MONTH, 1 , month + '-01' ) -
DATEADD( DAY, 7 - DATEPART( WEEKDAY, month + '-01' ), month + '-01' )
) DIV 7 + 1
I don't know how much ANSI SQL compatible this is but it works in MySql (not after the changes, it should work in SQL Server now).
month should be in 'yyyy-mm' format