Query
SELECT
DATENAME(dw, O1.CreationDateTime) AS 'Day of the week',
DATENAME(hh, O1.CreationDateTime) AS hour,
COUNT(*) AS 'Nr. Orders'
FROM
Orders AS O1
WHERE
O1.CreationDateTime >= '2015-10-01'
GROUP BY
DATENAME(dw, O1.CreationDateTime), DATENAME(hh, O1.CreationDateTime)
ORDER BY
[Day of the week], CAST(DATENAME(hh, O1.CreationDateTime) as int)
Gives the total number of orders for each hour of each weekday
Result
Weekday Hour Nr.Orders
Friday 0 10
Friday 1 11
Friday 2 2
The goal is to get the AVERAGE amount of orders for each hour of the day. However some days have no orders those days should not be counted.
To solve this problem I wrote the select distinct query below.
Query
SELECT
DATENAME(dw,Formatteddate.Date) AS "Day of the week",
COUNT(*) AS "Weekdays in period"
FROM
(SELECT DISTINCT
((CONVERT (date,O2.CreationDateTime,112))) AS Date
FROM Orders AS O2
WHERE
O2.CreationDateTime >= '2015-10-01'
) AS Formatteddate
GROUP BY DATENAME(dw,Formatteddate.Dates)
It counts for example the number of fridays with orders like shown below.
Result
Day of the week | Week days in period (with order)
Friday 32
Monday 30
Saturday 21
Basically my questions is how two merge those two query's I used outer
apply as a workaround. However it is very slow due to the fact it
checks each row. I think I need to use the over clause but I have no
idea how with the datename function.
The end result should look like this to make counting the average easy.
Weekday Hour Nr.Orders Weekdays in period
Friday 0 10 32
Friday 1 11 32
Friday 2 2 32
Friday 3 2 32
You can join the two tables together on the day of the week:
SELECT t1.[Day of the week] AS Weekday,
t1.hour,
t1.[Nr. Orders],
COALESCE(t2.[Weekdays in period], 0)
FROM
(
SELECT DATENAME(dw, O1.CreationDateTime) AS 'Day of the week',
DATENAME(hh, O1.CreationDateTime) AS hour,
COUNT(*) AS 'Nr. Orders'
FROM Orders AS O1
WHERE O1.CreationDateTime >= '2015-10-01'
GROUP BY DATENAME(dw, O1.CreationDateTime),
DATENAME(hh, O1.CreationDateTime)
) t1
LEFT JOIN
(
SELECT DATENAME(dw,Formatteddate.Date) AS "Day of the week",
COUNT(*) AS "Weekdays in period"
FROM
(
SELECT DISTINCT CONVERT (date,O2.CreationDateTime, 112) AS Date
FROM Orders AS O2
WHERE O2.CreationDateTime >= '2015-10-01'
) AS Formatteddate
GROUP BY DATENAME(dw,Formatteddate.Dates)
) t2
ON t1.[Day of the week] = t2.[Day of the week]
Try joining on the day:
WITH DayO AS (
SELECT
DATENAME(dw,Formatteddate.Date) AS DayOfWeek,
COUNT(*) AS PeriodDays
FROM
(SELECT DISTINCT
((CONVERT (date,O2.CreationDateTime,112))) AS Date
FROM Orders AS O2
WHERE
O2.CreationDateTime >= '2015-10-01'
) AS Formatteddate
GROUP BY DATENAME(dw,Formatteddate.Dates)
)
, HourO AS (
SELECT
DATENAME(dw, O1.CreationDateTime) AS DayOfWeek,
DATENAME(hh, O1.CreationDateTime) AS OrdHour,
COUNT(*) AS NumOrd
FROM
Orders AS O1
WHERE
O1.CreationDateTime >= '2015-10-01'
GROUP BY
DATENAME(dw, O1.CreationDateTime), DATENAME(hh, O1.CreationDateTime)
ORDER BY
[DayOfWeek], CAST(DATENAME(hh, O1.CreationDateTime) as int)
)
SELECT ho.DayOfWeek as Weekday, ho.OrdHour as Hour, ho.NumOrd as [Nr. Orders], DayO.PeriodDays as [Weekdays in period]
from HourO ho
inner join DayO
on ho.DayOfWeek = DayO.DayOfWeek
Related
I'm wondering how could I use the GROUP BY on month, but from the n-th of a month to the (n-1)-th of the next month. For exemple, I want to GROUP by from the 20 of january to the 19 of february, from the 20 of february to the 19 of march...
Currently I can GROUP BY Months and dates <20 with a condition. There is the demo :
https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=8b55b7df44350c4ad3c595d03e421b6e
But now I don't know how can I group the 'false' of a month (ie that the value is the sum for days > 20) with the 'true' of the next month.
Does anyone as a idea how to do that ?(maybe what i'm trying os not the good way how to do that)
For each date before the 20th you can subtract 1 month and group it with the previous month:
WITH cte AS (
SELECT CASE
WHEN DAY(Date) >= 20 THEN Date
ELSE DATEADD(mm, -1, Date)
END Date,
Value
FROM tablename
)
SELECT YEAR(Date) year, MONTH(Date) month, SUM(Value) val
FROM cte
GROUP BY YEAR(Date), MONTH(Date)
ORDER BY YEAR(Date), MONTH(Date)
Or you can change the CASE expression to:
CASE
WHEN DAY(Date) < 20 THEN Date
ELSE DATEADD(mm, 1, Date)
END
so that all dates after the 19th are grouped with the next month.
Or:
SELECT FORMAT(DATEADD(dd, -20, Date), 'yyyy-MM') year_month,
SUM(Value) val
FROM tablename
GROUP BY FORMAT(DATEADD(dd, -20, Date), 'yyyy-MM')
See the demo.
I need list of those employees who are absent one day before and one day after weekend in a week......like if some is absent in Friday and present on Monday should not be included in the list
Use datepart(weekday, ) to fetch all records relative to monday and friday.
Have a look at SET DATEFIRST function too.
select *
from your_table
where datepart(weekday, Date) = 5
or datepart(weekday, Date) = 1;
This will list all employee id that are absent on a Friday and the following Monday (+1 week). I set-up a calendar week from mininum date to maximum date from the table and get only Friday and Monday. Then get all empid that has no attendance in any of those dates.
with caldte as (
SELECT dateadd(day, rn - 1, t.mindte) as dates,
datepart(weekday, dateadd(day, rn - 1, t.mindte)) as weekday,
datepart(wk, dateadd(day, rn - 1, t.mindte)) as weeknum
FROM (
select row_number() OVER ( order by c.object_id ) AS rn
FROM sys.columns c) rns,
(select min(dte) as mindte, max(dte) as maxdte
from tbl) t
WHERE rn - 1 <= datediff(day, t.mindte, t.maxdte)
and datepart(weekday, dateadd(day, rn - 1, t.mindte)) in (2, 6)
)
select distinct empid
from tbl
where empid not in (
select t.empid
from caldte c, tbl t
where c.dates = t.dte)
order by empid
Good Day! I am working on a chart where I need to display all the days of the current week to show the sales per Week. So far, I am able to display all the days of the current week, I'm just having a trouble in displaying the sales for each day of the week.Since there are no records in the database for the days of the week, it the TOTAL_SALES column should all return a Null value. Instead, it returns the total sales recorded in the database. Here is my Stored Procedure query so far.
WITH DAYSOFTHEWEEK AS
(
SELECT 0 DAY
UNION ALL
SELECT DAY + 1 FROM DAYSOFTHEWEEK WHERE DAY < 6
)
SELECT DATEADD(DAY, DAY, DATEADD(DAY, 2-DATEPART(WEEKDAY, CONVERT (date, GETDATE())), CONVERT (date, GETDATE()))) AS DAY_OF_THE_WEEK,
SUM([ORDER].NET_AMOUNT) AS TOTAL_SALES
FROM DAYSOFTHEWEEK, [ORDER]
GROUP BY DAYSOFTHEWEEK.DAY
I tried adding this condition statement,
WHERE DAYSOFTHEWEEK.DAY IN ([ORDER].ORDER_DATE)
But it returns this error
Operand type clash: date is incompatible with int
Can someone help me out on this?Is there a work around with the code that I already have? Thanks in advance!
What I think you're after is a SUM of each day's sales for the current week with NULL if there are no sales. The secret is to left join your date list onto your data:
-- Setup some fake sales data
WITH TestData(N, Order_Date, Net_Amount) AS (
SELECT 1 N, CAST(GETDATE() AS DATE) Order_Date, RAND() * 100 Net_Amount
UNION ALL
SELECT N+1 N, CAST(GETDATE()-N/5 AS DATE) Order_Date, RAND(CHECKSUM(NEWID())) * 100 Net_Amount FROM TestData
WHERE N < 20
)
SELECT TestData.Order_Date, TestData.Net_Amount INTO #Order FROM TestData
--Set the first day of the week (if required)
SET DATEFIRST 7 --Sunday
;WITH Days(N,DayOfTheWeek) AS (
SELECT 1 N, DATEADD(DAY, 1-DATEPART(WEEKDAY, GETDATE()), CONVERT(DATE,GETDATE())) DayOfTheWeek
UNION ALL
SELECT N+1 N,DATEADD(DAY, 1, DayOfTheWeek) DayOfTheWeek FROM Days
WHERE N < 7
)
SELECT d.DayOfTheWeek, SUM(Net_Amount) TotalAmount
FROM Days d
LEFT JOIN #Order ON d.DayOfTheWeek = Order_Date
GROUP BY d.DayOfTheWeek
DayOfTheWeek TotalAmount
------------ ----------------------
2016-08-07 219.036784917497
2016-08-08 273.319570812461
2016-08-09 271.148114731087
2016-08-10 194.780039228967
2016-08-11 NULL
2016-08-12 NULL
2016-08-13 NULL
Here is every day this week, starting at your datefirst date, which can be temporarily varied for the query with SET DATEFIRST if you need to have some other week start date
I think you have some sales table there that you haven't shown us, you need to join to that on date, then group by
WITH DAYSOFTHEWEEK AS
(
SELECT cast(dateadd(
day,
-datepart(weekday,getdate()) + 1 ,
GETDATE()
)
as date) [DAY], 0 as cnt
UNION ALL
SELECT dateadd(day,1,[DAY]), cnt + 1 FROM DAYSOFTHEWEEK WHERE cnt < 6
)
select DAYSOFTHEWEEK.[day], SUM([ORDER].NET_AMOUNT) AS TOTAL_SALES from daysoftheweek
JOIN
SalesTable on
CAST(SalesTable.SalesDate date) = DAYSOFTHEWEEK.[day]
GROUP BY DAYSOFTHEWEEK.[day]
A little over complicated for me:
To get name of the week use, for example
SELECT DATENAME(dw,getdate())
But you really need something like this:
SELECT ProductName,Sum(Sales) From NameOfTable GROUP BY
DATENAME(ww,salesDate)
I try this SQL query to get current total and also last 2 months records and current month record means total 3 months..
Select distinct
tblRv.Owner,
(Select Count(*) as total from tblvv WHERE MasterID =tblRv.ID and Name <> '')
as currentdata
from tblRe
inner join tblRv
On tblRe.RID = tblRv.RID
WHERE
tblRe.StartDate between dateadd(m, -2, getdate()) and getdate() and
//tblRe.StartDate >= '2016-07-01 00:00:00' AND
//tblRe.EndDate <= '2016-07-08 23:59:59'
and tblRe.Region = 'uk' and
tblRv.Owner='Roh'
order by tblRv.Owner
when i exe this show me like this
OwnerName currentdata
Roh 1
Roh 2
Roh 3
Roh 5
and when i check individually write query and check from date 2016-07-01 and todate 2016-07-30 dates then this show me data 3 and 2016-06-01 00:00:00 and 2016-06-31 23:59:59 show me data 1 and 2016-05-01 00:00:00 ,2016-05-31 23:59:59 show me data 0
so i want data like this
owner july june may
roh 3 1 0
also when there will be current month i.e. aug then data must display last 2 months i.e.june july
Select
tblRv.Owner
,DATENAME(MONTH,tblRe.StartDate) as [Month]
,ISNULL(SUM(total),0) as currentdata
from tblRe
INNER JOIN tblRv ON tblRe.RID = tblRv.RID
LEFT JOIN (
Select Count(*) as total ,MasterID
from tblvv
WHERE Name <> ''
GROUP BY MasterID
) tblvv
ON tblvv.MasterID =tblRv.ID
WHERE tblRe.StartDate >= DATEADD(MONTH, -2, GETDATE())
AND tblRe.EndDate <= GETDATE()
AND tblRe.Region = 'uk'
AND tblRv.[Owner] ='Roh'
GROUP BY tblRv.Owner
,DATENAME(MONTH,tblRe.StartDate)
order by tblRv.[Owner]
You can try doing a pivot query where the three columns to be pivoted are the current, previous, and previous previous month in your data set. Note that I had to rewrite your query to remove the subqueries in the SELECT clause, because this makes it impossible to do aggregation of those columns.
SELECT tblRv.Owner,
SUM(CASE WHEN tblRe.StartDate = GETDATE() THEN t.total ELSE 0 END) AS currMonth,
SUM(CASE WHEN tblRe.StartDate = DATEADD(m, -1, GETDATE())
THEN t.total ELSE 0 END) AS prevMonth,
SUM(CASE WHEN tblRe.StartDate = DATEADD(m, -2, GETDATE())
THEN t.total ELSE 0 END) AS lastPrevMonth
FROM tblRe
INNER JOIN tblRv
ON tblRe.RID = tblRv.RID
INNER JOIN
(
SELECT MasterID, COUNT(*) AS total
FROM tblvv
GROUP BY MasterID
WHERE Name <> ''
) AS t
ON tblRv.ID = t.MasterID
WHERE tblRe.StartDate BETWEEN DATEADD(m, -2, GETDATE()) AND GETDATE() AND
tblRe.Region = 'uk' AND
tblRv.Owner = 'Roh'
GROUP BY tblRv.Owner
ORDER BY tblRv.Owner
In a view have these two dates coming from a table:
2014-12-17 14:01:03.523 - 2014-12-20 09:59:28.783
I need to know the date diff in hours assuming that in a day i can count the hours just from 08 AM and 5 PM.
Of course saturdays and sundays must not be included.
I tried using this code inside the select but i only got the diff in days, excluding saturdays and sundays.
(DATEDIFF(HOUR, convert(datetime,t.EXT_DATAINS-2), convert(datetime,b.EXT_DATAINS-2)) + 1)
-(DATEDIFF(wk, convert(datetime,t.EXT_DATAINS-2), convert(datetime,b.EXT_DATAINS-2)) * 2)
-(CASE WHEN DATENAME(dw, convert(datetime,t.EXT_DATAINS-2)) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, convert(datetime,b.EXT_DATAINS-2)) = 'Saturday' THEN 1 ELSE 0 END) differenza
Example:
2014-12-17 : 3hrs
2014-12-18 : 8hrs
2014-12-19 : 8hrs
2014-12-20 : 2hrs
Tot : 21hrs
Use a Recursive CTE to get all Hours with Dates.
METHOD 1 : Get all dates with hours between FromDate and ToDate
DECLARE #FROMDATE DATETIME='2014-12-17 14:01:03.523'
DECLARE #TODATE DATETIME='2014-12-20 09:59:28.783'
;WITH CTE AS
(
SELECT #FROMDATE FROMDATE
UNION ALL
SELECT DATEADD(HH,1,FROMDATE)
FROM CTE
WHERE FROMDATE<#TODATE
)
SELECT ISNULL(CAST(CAST(FROMDATE AS DATE)AS VARCHAR(12)),'Tot')FROMDATE,
CAST(COUNT(FROMDATE)AS VARCHAR(4))+'hrs' [HOURS]
FROM CTE
WHERE DATEPART(HH,FROMDATE) BETWEEN 9 AND 16
AND DATENAME(DW,FROMDATE)<>'SATURDAY' AND DATENAME(DW,FROMDATE)<>'SUNDAY'
GROUP BY CAST(FROMDATE AS DATE)
WITH ROLLUP
SQL FIDDLE
METHOD 2 : Gets missing dates between FromDate and ToDate with 8 as hardcoded as Hrs
This method will be more implementable - Performance Tuned
DECLARE #FROMDATE DATETIME='2014-12-17 14:01:03.523'
DECLARE #TODATE DATETIME='2014-12-20 09:59:28.783'
;WITH CTE AS
(
-- Get missing dates between FromDate and ToDate
SELECT DATEADD(DAY,1,#FROMDATE) FROMDATE,8 HRS
UNION ALL
SELECT DATEADD(DAY,1,FROMDATE),8
FROM CTE
WHERE FROMDATE < DATEADD(DAY,-1,#TODATE)
)
,CTE2 AS
(
-- Gets the Hours for FromDate
SELECT CAST(#FROMDATE AS DATE) DATES, CAST(CAST(DATEDIFF
(
MINUTE,#FROMDATE,CAST(CAST(CAST(#FROMDATE AS DATE) AS VARCHAR(12))+' 17:00:00' AS DATETIME)
)AS NUMERIC(18,2))/60 AS DECIMAL(18,0)) HRS
WHERE DATENAME(DW,#FROMDATE)<>'SATURDAY' AND DATENAME(DW,#FROMDATE)<>'SUNDAY'
UNION ALL
-- Select Hours in between dates
SELECT CAST(FROMDATE AS DATE) NEWDATE,HRS
FROM CTE
WHERE DATENAME(DW,FROMDATE)<>'SATURDAY' AND DATENAME(DW,FROMDATE)<>'SUNDAY'
UNION ALL
-- Select Hours for ToDate
SELECT CAST(#TODATE AS DATE), CAST(CAST(DATEDIFF
(
MINUTE,CAST(CAST(CAST(#TODATE AS DATE) AS VARCHAR(12))+' 08:00:00' AS DATETIME),#TODATE
)AS NUMERIC(18,2))/60 AS DECIMAL(18,0))
WHERE DATENAME(DW,#TODATE)<>'SATURDAY' AND DATENAME(DW,#TODATE)<>'SUNDAY'
)
-- Use ROLLUP to find the sum of Hours and show it in last row
SELECT ISNULL(CAST(DATES AS VARCHAR(20)),'Tot')DATES,
CAST(SUM(HRS)AS VARCHAR(4))+'hrs' HRS
FROM CTE2
GROUP BY DATES
WITH ROLLUP
SQL FIDDLE
#marco burrometo
Create a static table which will have all the calendar functionality like holiday functionality,saturday and sunday is a holiday. It will help you a lot.