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.
Related
I have my daily totals to get the sum of all orders which is filtered by the EntryDate.
Now, I want to have it as a basis for me to filter the DueDate instead of EntryDate for the CurrentMonth.
How to do that?
How would I edit the WHERE clause?
My current code now is:
SELECT
CONVERT(varchar, GETDATE(), 103) AS Date, 'Sales Orders' AS Type, COUNT(SalesOrderID) AS Qty, '$' + CONVERT(VARCHAR(20), ISNULL(ROUND(SUM(SubTotal), 2),0)) AS [Total Ex GST]
FROM dbo.SalesOrder
WHERE (DateCreated > CONVERT(int, GETDATE() - 0.5))
try this query:
select
dateadd(mm,datediff(mm,0,getdate()),0) AS [1st Day of Current Month]
, dateadd(mm,datediff(mm,0,getdate())+1,0) AS [1st Day of Next Month]
so your where clause for "DueDate instead...for the current month" might look like this:
where DueDate >= dateadd(mm,datediff(mm,0,getdate()),0)
and DueDate < dateadd(mm,datediff(mm,0,getdate())+1,0)
What these functions do is:
calculate the number of months from the current date/time from zero (which is the base date of 1900-01-01 in SQL Server)
then add the number of months to zero (i.e. 1900-01-01) to calculate first day of the current month, and
add 1 to the number of months and this calculates the first day of the next month
I have amended the code and it works fine:
SELECT dateadd(mm,datediff(mm,0,getdate()),0) AS [1st Day of Current Month]
, 'Sales Orders' AS Type
, COUNT(SalesOrderID) AS Qty
, '$' + CONVERT(VARCHAR(20), ISNULL(ROUND(SUM(SubTotal), 2), 0)) AS [Total Ex GST]
FROM dbo.SalesOrder
WHERE DueDate >= dateadd(mm,datediff(mm,0,getdate()),0)
AND DueDate < dateadd(mm,datediff(mm,0,getdate())+1,0)
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'm attempting to get a count of items within a 7-day period, while still being able to report the first date of said seven day period. The closest I've come so far is
WITH w (w, n)
AS
(
SELECT MIN(CAST(CreatedDate AS DATE))
OVER(
PARTITION BY DATEPART(WEEK, CAST(CreatedDate AS DATE))
ORDER BY DATEPART(WEEK, CAST(CreatedDate AS DATE))
)
,COUNT(*)
FROM dbo.Tbl
WHERE
CreatedDate >= CAST(DATEADD(MONTH,-6,GETDATE()) AS DATE)
GROUP BY CAST(CreatedDate AS DATE)
)
SELECT w.w AS [Week of], SUM(w.n) AS [Items]
FROM w
GROUP BY w.w
ORDER BY 1 DESC
But this unfortunately does not work for the first or last week of the year, and will not work if the date range includes more than one year.
Is there a way to group by a seven day period while still being able to get the first date in said period?
You can use the following to get your weeks based on your date value. You will need to play around with the days added to get the right days of the week for your situation, but you will always be guaranteed the same start and end day. In this case the week starts on Sunday and ends on Saturday:
declare #Date datetime
set #Date = '20160802'
select #Date - DATEPART(dw, #Date) + 1 as FirstDateOfWeek
,#Date + (7 - DATEPART(dw, #Date)) as LastDateOfWeek
For a fully bulletproof solution you could add in logic to check and use ##DATEFIRST and assign the adjustment values accordingly.
Once you have your week start value, you can use that in your group by:
select CreatedDate - DATEPART(dw, #Date) + 1 as FirstDateOfWeek
,count(*)
from tbl
group by CreatedDate - DATEPART(dw, #Date) + 1
order by FirstDayOfWeek
I have tried searching for a soln to this but have been unable yet to find one.
I need to select the last 4 weeks of data from todays date which is not the issue as I just do a date >= Dateadd(mm, -1, getdate()). However I also want the same 4 weeks of data from the previous year. But I dont want (for example) June 1-30 2010 and June 1-30 2011, I would need
June 30th (thursday) 2011 and 4 weeks prior AND July 1st and four weeks prior as july 1st was the thursday in the same week from the prev year.
so 8 weeks of data would be returned.
Thanks for the help!
You can use some more DATEADD() goodness to go back to the previous year:
where theDate >= DATEADD(mm, -1, GETDATE())
OR
(theDate <= DATEADD(week,-52,convert(datetime,GETDATE()))
and
theDate >= DATEADD(mm,-1,DATEADD(week,-52,convert(datetime,GETDATE()))))
Subtracting 52 weeks from 6/30/2011 returns 7/1/2010 as you requested... Then using your original subtraction of 1 month from there for the lower bound.
You could also switch the whole thing to use weeks...
where theDate >= DATEADD(week, -4, GETDATE())
OR
(theDate <= DATEADD(week,-52,convert(datetime,GETDATE()))
and
theDate >= DATEADD(week,-56,convert(datetime,GETDATE())))
you may do a serial of ORed BETWEEN conditions:
select
...
from
...
where
1=1
or date between Dateadd(mm, -2, getdate()) and Dateadd(mm, -1, getdate())
or date between Dateadd(mm, -11, getdate()) and Dateadd(mm, -10, getdate())
order by
date
did i understand right?
Last four weeks sales data:
with cte as (
select case when row_number() OVER (ORDER BY DATEPART(wk,CreatedDate) DESC) = 2 then 'last 1st Week'
when row_number() OVER (ORDER BY DATEPART(wk,CreatedDate) DESC) = 3 then 'last 2nd Week'
when row_number() OVER (ORDER BY DATEPART(wk,CreatedDate) DESC) = 4 then 'last 3rd Week'
when row_number() OVER (ORDER BY DATEPART(wk,CreatedDate) DESC) = 5 then 'last 4th Week'
else 'last 5th plusweek'
end as weeks,
sum(amt) as week_wise_sale,
row_number() OVER (ORDER BY DATEPART(wk,CreatedDate) DESC) AS [row number]
from samt
group by DATEPART(wk,CreatedDate)
) select * from cte where [ROW NUMBER] > 1