Compare Monday's data to previous Mondays in SQL Server - sql

I am trying to figure out how to compare the current day's data to the same data from a week ago, 2 weeks, etc. Let's say I have a table called "Order" with 2 columns:
Order table
-----------
OrderID int identity
OrderDate datetime
If today, is Monday, I would like to be able to compare the number of orders from today to the previous Mondays for an entire year. Is this possible with a single SQL Server query? I'm using SQL 2008 if it makes a difference.

select CAST (OrderDate as date) as [Date], COUNT(*)
from Orders
where OrderDate > DATEADD(YEAR,-1, getdate())
and DATEPART(DW,OrderDate ) = DATEPART(DW,GETDATE())
group by CAST (OrderDate as date)

Try
SELECT [ColumnsYouWant]
FROM [OrderTable]
WHERE datepart(weekday, OrderDate) = datepart(weekday, getdate())
AND OrderDate >= dateadd(yyyy, -1, getdate())

This gives you Monday order counts by week number:
select year(OrderDate) as Year,
DATEPART(WEEK, OrderDate) as Week,
COUNT(*) as MondayOrderCount
from Order
where DATEPART(WEEKDAY, OrderDate) = 2
group by year(OrderDate), DATEPART(WEEK, OrderDate)
order by Year, Week

Related

Trying to get an SQL command that gets the new customers from each month but i cant seem to get it working

I am trying to pull the new customers from each month from an SQL database. I've tried this:
SELECT COUNT (Name)
FROM Customer
WHERE Date_created BETWEEN CONVERT(date, getdate()) AND CONVERT(date, getdate()) - (30)
From your query I think this would do it simpler :
SELECT COUNT (Name) FROM Customer WHERE MONTH(Date_created)= MONTH(GETDATE())
although am not sure this is what you expect as your question could be interpreted in several ways
Edit : taking account of different years:
SELECT COUNT (Name) FROM Customer
WHERE MONTH(Date_created)= MONTH(GETDATE())
AND YEAR(Date_created)= YEAR(GETDATE())
Standard SQL:
select
extract(year from Date_created) as yr
,extract(month from Date_created) as mth
,count(*)
from Customer
group by
extract(year from Date_created) as yr
,extract(month from Date_created) as mth
order by yr, mth
Replace EXTRACT with a matching function in you DBMS, e.g. for SQL Server datepart(year, date)
You could use convert(varchar(6), getdate(), 112) to get the month in yyyymm format:
SELECT convert(varchar(6), getdate(), 112) as Month
, count(*)
FROM Customer
GROUP BY
convert(varchar(6), getdate(), 112)
I'm not a fan of using BETWEEN with dates (see this blog What do BETWEEN and the Devil Have in Common). However, the problem with your query is that the dates are in the wrong order. The smaller value has to go first:
SELECT COUNT(Name)
FROM Customer
WHERE Date_created BETWEEN CONVERT(date, getdate() - 30) AND CONVERT(date, getdate())
This is better written as :
SELECT COUNT(Name)
FROM Customer
WHERE Date_Created >= CONVERT(date, getdate() - 30) AND
Date_Created < CONVERT(date, getdate());
I'm not sure if this satisfies your definition of "month", but at least the query will return 30 days worth of creates.

SELECT SQL data based on date, fill month

I'm selecting year, month and net sales from invoice table. The problem is that if there's no data under specific month, there will be no rows for that month. Can you help me? Net sales should be zero if there is not any data.
SELECT
DATEPART(year, date) as 'year',
DATEPART(month, date) as 'month',
SUM(netsales) as netsales
FROM invoice
WHERE
date >= '2015-01-01'
AND date <= '2016-12-31'
GROUP BY
DATEPART(year, date),
DATEPART(month, date)
Thanks in advance.
You need a calendar table and left join
;with calendar as
(
select cast('2015-01-01' as date) as dates -- start date
union all
select dateadd(mm,1,dates) from cte where dates < '2016-12-31' -- end date
)
SELECT
DATEPART(year, c.dates) as 'year',
DATEPART(month, c.dates) as 'month',
SUM(netsales) as netsales
FROM calendar C left join invoice i on c.dates = cast(i.[date] as date)
GROUP BY
DATEPART(year, date),
DATEPART(month, date)
I have generates dates on the fly using Recursive CTE, but I will always suggest to create a calendar table physically and use it in such queries

Group by Weeks for successive years

I am trying to aggregate data by weeks. My sample query looks like
SET DATEFIRST 1
Select ID,
DATENAME(week, p.SellingDate) as SellingWeek,
DATENAME(year, p.SellingDate) as SellingYear,
SUM(Quantity),
SUM(Revenue)
From dbo.Sales
Where
p.SellingDate >=’2015-12-20’ and P.SellingDate < ’2016-02-27’
Group by ID,
DATENAME(week, p.SellingDate),
DATENAME(year, p.SellingDate)
When I try to do this, I am facing an issue:
The query returns correct data but the issue appears in the last week of 2015. It considers only the days (12/28 to 12/31) that are part of 2015 as the 53rd week and it considers the remaining part (01/01 to 01/03) as a new week of 2016. I only one row that has data for the whole week i.e. 12/28 to 01/03) but SQL Server returns 2 rows. Is there a workaround this?
I would think you want to create a construct for grouping on week start and week end, then using that to group by for your aggregation clauses.
SET DATEFIRST 1
Select DATEADD(dd, -(DATEPART(dw, p.SellingDate)-1), p.SellingDate) AS [WeekStart],
DATEADD(dd, 7-(DATEPART(dw, p.SellingDate)), p.SellingDate) AS [WeekEnd],
SUM(Quantity),
SUM(Revenue)
From dbo.Sales
Where
p.SellingDate >= '2015-12-20' and P.SellingDate < '2016-02-27'
Group by ID,
DATEADD(dd, -(DATEPART(dw, p.SellingDate)-1), p.SellingDate),
DATEADD(dd, 7-(DATEPART(dw, p.SellingDate)), p.SellingDate)
You can fix this by setting the week not based on the date of the sale but rather on the monday of week of the date of the sale.
select
getdate() as today
datename(week, dateadd(dd,-1* (datepart(weekday, getdate())-1),getdate())) as monday,

SQL get Monthly, and weekly data

I am writing a query to give me number of products sold this week, this month and this year (3 separate columns) on a week to date, month to date and year to date scale meaning today for example it will show products sold since monday, since the first of the month and since first of the year and this is to continue with each following week, month and year as time goes, there also are to be 3 other columns with the same logic for last year. What i need is help getting the date query using DATEADD or DATEDIFF (example (DATEADD(minute, -15, GETDATE())).
thank you very much and also i'm using SQL Server 2008
Here is some untested code which could probably be optimized, but should get you going in the right direction. This uses a PIVOT operation to transform your rows into columns.
SELECT WeekCount, MonthCount, YearCount
FROM
(
SELECT ProductId,
CASE
WHEN ProductSoldDate >= DATEADD(dd, 1 - DATEPART(dw, GETDATE()), GETDATE())
THEN 'WeekCount'
WHEN ProductSoldDate >= DATEADD(mm, DATEDIFF(mm,0,GETDATE()), 0)
THEN 'MonthCount'
WHEN ProductSoldDate >= DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0)
THEN 'YearCount'
END as lbl
FROM Products
) ProductSales
PIVOT
(
COUNT(ProductId)
FOR lbl IN ([WeekCount], [MonthCount], [YearCount])
) t
Here is the SQL Fiddle.
Good luck.
Using the DATEADD function
In some circumstances, you might want to add an interval of time to a DATETIME or SMALLDATETIME value or subtract an interval of time. For example, you might need to add or subtract a month from a specific date. You can use the DATEADD function to perform this calculation. The function takes the following syntax:
DATEADD(date/time_part, number, date)
Example:
SELECT OrderDate, DATEADD(mm, 3, OrderDate) AS NewDate
FROM Sales.Orders
WHERE OrderID = 1001
Using the DATEDIFF function
The DATEDIFF function calculates the time interval between two dates and returns an integer that represents the interval. The function takes the following syntax:
DATEDIFF(date/time_part, start_date, end_date)
Example:
SELECT OrderDate, DelivDate,
DATEDIFF(hh, OrderDate, DelivDate) AS HoursDiff
FROM Sales.Orders
WHERE OrderID = 1002

SQL Hurdle - SQL Server 2008

The following query returns the total amount of orders, per week, for the past 12 months (for a specific customer):
SELECT DATEPART(year, orderDate) AS [year],
DATEPART(month, orderDate) AS [month],
DATEPART(wk, orderDate) AS [week],
COUNT(1) AS orderCount
FROM dbo.Orders (NOLOCK)
WHERE customerNumber = #custnum
AND orderDate >= DATEADD(month, -12, GETDATE())
GROUP BY DATEPART(year, orderDate),
DATEPART(wk, orderDate),
DATEPART(month, orderDate)
ORDER BY DATEPART(year, orderDate),
DATEPART(wk, orderDate)
This returns results like:
year month week orderCount
2008 1 1 23
2008 3 12 5
...
As you can see, only weeks that have orders for this customer will be returned in the resultset. I need it to return a row for every week in the past 12 months... if no order exists in the week then returning 0 for orderCount would be fine, but I still need the year, week, and month. I can probably do it by creating a separate table storing the weeks of the year, then left outer join against it, but would prefer not to. Perhaps there's something in SQL that can accomplish this? Can I create a query using built in functions to return all the weeks in the past 12 months with built in SQL functions? I'm on SQL Server 2008.
Edit:
Using Scott's suggestion I posted the query solving this problem below.
You could join to a recursive CTE - something like below should give you a start...
WITH MyCte AS
(SELECT MyWeek = 1
UNION ALL
SELECT MyWeek + 1
FROM MyCte
WHERE MyWeek < 53)
SELECT MyWeek,
DATEPART(year, DATEADD(wk, -MyWeek, GETDATE())),
DATEPART(month, DATEADD(wk, -MyWeek, GETDATE())),
DATEPART(wk, DATEADD(wk, -MyWeek, GETDATE()))
FROM MyCte
The table method you are already aware is the best way to go. Not only does it give you alot of control, but it is the best performing.
You could write sql code (user function) to do this, but it won't be as flexible. RDBMs are made for handling sets.
Solution using CTE: (thanks to Scott's suggestion)
;WITH MyCte AS
(SELECT MyWeek = 1
UNION ALL
SELECT MyWeek + 1
FROM MyCte
WHERE MyWeek < 53)
SELECT myc.[year],
myc.[month],
myc.[week],
isnull(t.orderCount,0) AS orderCount,
isnull(t.orderTotal,0) AS orderTotal
FROM (SELECT MyWeek,
DATEPART(year, DATEADD(wk, -MyWeek, GETDATE())) AS [year],
DATEPART(month, DATEADD(wk, -MyWeek, GETDATE())) AS [month],
DATEPART(wk, DATEADD(wk, -MyWeek, GETDATE())) AS [week]
FROM MyCte) myc
LEFT OUTER JOIN
(SELECT DATEPART(year, orderDate) AS [year],
DATEPART(month, orderDate) AS [month],
DATEPART(wk, orderDate) AS [week],
COUNT(1) AS orderCount,
SUM(orderTotal) AS orderTotal
FROM dbo.Orders (NOLOCK)
WHERE customerID = #custnum
AND orderDate >= DATEADD(month, -12, GETDATE())
GROUP BY DATEPART(year, ODR_DATE),
DATEPART(wk, orderDate),
DATEPART(month, orderDate)) t ON t.[year] = myc.[year] AND t.[week] = myc.[week]
ORDER BY myc.[year],
myc.[week]
Edit: just noticed one week is being duplicated (2 records for the same week)... probably a simple logical error... disregard... ID-10-T... apparently a week can span months... who would have known lol
In the past I've done this using the table approach that you mention, the other way was to create a table function that I could pass arguments to specifying the start and end range that I wanted and it would build results dynamically to save needing to add a table with all the data.