Select SQL results grouped by weeks - sql-server

I want to select data from following table group by weeks
Date Product Name Sale
+----------+--------------+-----+
14-05-11 a 2
14-05-11 b 4
17-05-11 c 3
19-05-11 a 6
24-05-11 a 6
29-05-11 a 6
Let suppose today is 30-05-11
So my result should look like this.
Product Name First Week Second Week Third Week
+--------------------+------------+------------+-------------+
a 12 6 2
b 0 0 4
c 0 3 0
Will some body guide me to how to write SQL query to achieve this behavior!

I think this should do it..
Select
ProductName,
WeekNumber,
sum(sale)
from
(
SELECT
ProductName,
DATEDIFF(week, '2011-05-30', date) AS WeekNumber,
sale
FROM table
)
GROUP BY
ProductName,
WeekNumber

the provided solutions seem a little complex? this might help:
https://msdn.microsoft.com/en-us/library/ms174420.aspx
select
mystuff,
DATEPART ( year, MyDateColumn ) as yearnr,
DATEPART ( week, MyDateColumn ) as weeknr
from mytable
group by ...etc

This should do it for you:
Declare #DatePeriod datetime
Set #DatePeriod = '2011-05-30'
Select ProductName,
IsNull([1],0) as 'Week 1',
IsNull([2],0) as 'Week 2',
IsNull([3],0) as 'Week 3',
IsNull([4],0) as 'Week 4',
IsNull([5], 0) as 'Week 5'
From
(
Select ProductName,
DATEDIFF(week, DATEADD(MONTH, DATEDIFF(MONTH, 0, InputDate), 0), InputDate) +1 as [Weeks],
Sale as 'Sale'
From dbo.YourTable
-- Only get rows where the date is the same as the DatePeriod
-- i.e DatePeriod is 30th May 2011 then only the weeks of May will be calculated
Where DatePart(Month, InputDate)= DatePart(Month, #DatePeriod)
)p
Pivot (Sum(Sale) for Weeks in ([1],[2],[3],[4],[5])) as pv
It will calculate the week number relative to the month. So instead of week 20 for the year it will be week 2. The #DatePeriod variable is used to fetch only rows relative to the month (in this example only for the month of May)
Output using my sample data:

Base on #increddibelly answer, I applied to my query as below.
I share for whom concerned.
My table structure FamilyData(Id, nodeTime, totalEnergy)
select
sum(totalEnergy) as TotalEnergy,
DATEPART ( week, nodeTime ) as weeknr
from FamilyData
group by DATEPART (week, nodeTime)

Declare #DatePeriod datetime
Set #DatePeriod = '2011-05-30'
Select ProductName,
IsNull([1],0) as 'Week 1',
IsNull([2],0) as 'Week 2',
IsNull([3],0) as 'Week 3',
IsNull([4],0) as 'Week 4',
IsNull([5], 0) as 'Week 5'
From
(
Select ProductName,
DATEDIFF(week, DATEADD(MONTH, DATEDIFF(MONTH, 0, '2011-05-30'), 0), '2011-05-30') +1 as [Weeks],
Sale as 'Sale'
From dbo.WeekReport
-- Only get rows where the date is the same as the DatePeriod
-- i.e DatePeriod is 30th May 2011 then only the weeks of May will be calculated
Where DatePart(Month, '2011-05-30')= DatePart(Month, #DatePeriod)
)p
Pivot (Sum(Sale) for Weeks in ([1],[2],[3],[4],[5])) as pv
OUTPUT LOOK LIKE THIS
a 0 0 0 0 20
b 0 0 0 0 4
c 0 0 0 0 3

Related

Select all days of the current week

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)

Last 2 month record in SQL

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

Quickest way to get aggregate date statistics / pivot

I am tryig to write what must be a fairly common audit report; number of rows added to a table over time; reported back against previous cycles to understand the trends in the data.
I have a table that audits creation of rows in the database. It has a field RowEnteredDate date time. I am looking to create an audit report Week/ Month/ Current Quarter / Year.
In my head I am looking at this as multiple passes over the data around the dates; which is quite costly in my database. My reasoning at the moment is
I started out with working out the dates for my year / month / quarter
set datefirst 1
declare #dateranges table (
rangelabel varchar(100),
startdate datetime,
enddate datetime,
myrowcount integer identity(1,1)
)
insert into #dateranges (Rangelabel, startdate, enddate)
select
'Current Year',
DATEADD(yy, DATEDIFF(yy,0,GETDATE()), 0),
DATEADD(ms,-3,DATEADD(yy, DATEDIFF(yy,0,GETDATE() )+1, 0))
insert into #dateranges (Rangelabel, startdate, enddate)
select
'Current Quarter',
DATEADD(qq, DATEDIFF(qq,0,GETDATE()), 0),
DATEADD(qq, DATEDIFF(qq, - 1, getdate()), - 1)
insert into #dateranges (Rangelabel, startdate, enddate)
select
'Current Month',
DATEADD(month, DATEDIFF(month, 0, getdate()), 0),
DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+1,0))
If my table is tblOfUsefullFacts and my date row is RowEnteredDate what is the best way to get the aggregate; broken by Day.
Date Range Mon Tues Wed Thu Fri Sat Sun
Year To date 12000 13000 12000 3200 98000 8900 4000
Quarter 1 302 407 201 97 1732 120 37
Month ...
I can get the totals by day easily enough using a query like this
select
count(*) ,
datepart(weekday, RowEnteredDate)
from
tblOfUsefullFacts aa
Where
datepart(weekday, RowEnteredDate) is not null
group by datepart(weekday, RowEnteredDate)
order by datepart(weekday, RowEnteredDate) sac
This selects the data out row by row; which i could pivot and loop round to get the data. Im slightly nervous as the real numbers are in the 10's of millions in them and would like to not impact the underlying processing if i can avoid it.
As i need to do this in multiple passes is there a lighter way to do this without running the loops to get the totals? Or a mechanism in SQL my fuzzy brain is ignoring.
This should give you an idea how to do it. Sorry for any syntax errors, it isn't tested.
;with cte as
(
select
d.rangelabel,
datepart(weekday, RowEnteredDate) as WkDay,
count(*) as RowCt
from tblOfUsefullFacts f
join #dateranges d on f.RowEnteredDate between d.startdate and d.enddate
Where datepart(weekday, RowEnteredDate) is not null
group by d.rangelabel,datepart(weekday, RowEnteredDate)
)
select
RangeLabel,
sum(case when WkDay = 1 then RowCt else 0 end) as Sunday,
sum(case when WkDay = 2 then RowCt else 0 end) as Monday,
sum(case when WkDay = 3 then RowCt else 0 end) as Tuesday,
sum(case when WkDay = 4 then RowCt else 0 end) as Wednesday,
sum(case when WkDay = 5 then RowCt else 0 end) as Thursday,
sum(case when WkDay = 6 then RowCt else 0 end) as Friday,
sum(case when WkDay = 7 then RowCt else 0 end) as Saturday
from cte
group by RangeLabel

How to count the number of days in a given month and in a given year in MSSQL

EmployeeID RecordID DateRecord
1 1 2/19/2013 12:00:00 AM
1 2 2/21/2013 12:00:00 AM
1 3 2/23/2013 12:00:00 AM
1 4 2/27/2013 12:00:00 AM
1 5 3/3/2013 12:00:00 AM
2 11 3/10/2013 12:00:00 AM
2 12 3/14/2013 12:00:00 AM
1 14 3/16/2013 12:00:00 AM
How can I count the number of days?
Example in February 2013 which has "19, 21, 23, 27" that should be count to "4" days .. ??
I found this method ..
SELECT DATEPART(yy, Daterecord),
DATEPART(mm, Daterecord),
DATEPART(dd, Daterecord),
COUNT(*)
FROM Records
GROUP BY DATEPART(yy, Daterecord),
DATEPART(mm, Daterecord),
DATEPART(dd, Daterecord)
and resulted to ..
2013 2 19 1
2013 2 21 1
2013 2 23 1
2013 2 27 1
2013 3 3 1
2013 3 10 1
2013 3 14 1
2013 3 16 1
it just get the specific dates but didm't count the total number of days in each month .. help me .. pls
I have change few names hopr you won't mind
WITH Emp_CTE AS (
SELECT EmployeeID ,DATEPART(yy, Daterecord) AS years,
DATEPART(mm, Daterecord) AS months
-- DATEPART(dd, Daterecord) AS days
FROM testTrial
)
SELECT COUNT(months) AS noOfMonths ,* FROM Emp_CTE GROUP BY months,EmployeeID,years
SqlFiddle
Let you try this:-
1: Find the number of days in whatever month we're currently in
DECLARE #dt datetime
SET #dt = getdate()
SELECT #dt AS [DateTime],
DAY(DATEADD(mm, DATEDIFF(mm, -1, #dt), -1)) AS [Days in Month]Solution
2: Find the number of days in a given month-year combo
DECLARE #y int, #m int
SET #y = 2012
SET #m = 2
SELECT #y AS [Year],
#m AS [Month],
DATEDIFF(DAY,
DATEADD(DAY, 0, DATEADD(m, ((#y - 1900) * 12) + #m - 1, 0)),
DATEADD(DAY, 0, DATEADD(m, ((#y - 1900) * 12) + #m, 0))
) AS [Days in Month]
If your table is called Employee then this will do the trick:
select convert(varchar, DateRecord, 112)/ 100, count(*)
from Employee
group by convert(varchar, DateRecord, 112)/ 100
Your initial query was almost right, just needed to remove the DATEPART(dd, Daterecord) from the grouping and it would work. Add in a HAVING clause to find the records from the month of February:
SELECT
DATEPART(yy, Daterecord),
DATEPART(mm, Daterecord),
COUNT(1)
FROM
Records
GROUP BY
DATEPART(yy, Daterecord),
DATEPART(mm, Daterecord)
HAVING
DATEPART(yy, eCreationTime) = 2013
AND DATEPART(mm, Daterecord) = 2
there is no 'yearmonth' in the suggested code ??
try this perhaps
select
datename(month,daterecord) as [Month]
, year(DateRecord) as [Year]
, count(distinct DateRecord ) as day_count
, count(distinct dateadd(day, datediff(day,0, DateRecord ), 0)) as daytime_count
from your_table
where ( DateRecord >= '20130201' and DateRecord < '20130301' )
group by
datename(month,daterecord)
, year(DateRecord)
note the column [daytime_count] is only required if the field [DateRecord] has times othe than 12:00 AM (i.e. it "trims off" times so you deal with dates at 12:AM)
Regarding date range selections: many people will feel that using 'between' is the solution however that isn't true and the safest most reliable method is as I shown above. Note that the higher date is 1st March, but we are asking for information that is less than the 1st March, so we don't need to worry about leap years and we don't have to worry about hours and minutes either.
see: What do BETWEEN and the devil have in common?
try this...
declare #date2 nvarchar(max)
set #date2 = (select getdate())
select DateDiff(Day,#date2,DateAdd(month,1,#date2))

SQL Server Select last 4 weeks from now and same period from last year only

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

Resources