SQL Server : number of orders per date with day column - sql

I have a query that pulls number of orders per date.
SELECT
name, CONVERT(VARCHAR(10), order_date, 120) AS order_date,
COUNT(1) AS orders
FROM
orders AS od
WHERE
id = 73
GROUP BY
CONVERT(VARCHAR(10), order_date, 120), name
ORDER BY
order_date, name
Below are the results I get when I run the query:
name order_date orders
--------------------------
20pmam 2016-07-27 39
20pmam 2016-07-28 30
20pmam 2016-07-29 32
20pmam 2016-07-31 468
20pmam 2016-08-02 75
20pmam 2016-07-05 30
I need my results to be like this, with a new column day
name order_date orders day
-------------------------------
20pmam 2016-07-27 39 1
20pmam 2016-07-28 30 2 // days between 2016-07-27 to 2016-07-28
20pmam 2016-07-29 32 3 // days between 2016-07-27 to 2016-07-29
20pmam 2016-07-31 468 5 // days between 2016-07-27 to 2016-07-31
20pmam 2016-08-02 75 7 // days between 2016-07-27 to 2016-08-02
20pmam 2016-08-05 30 10 // days between 2016-07-27 to 2016-08-05
The first/minimum order_date should be taken as day 1 ( in the above results 2016-07-27 is day 1) and should calculate others based on the first/minimum order_date.
Is this easily possible?
I don't have any idea how to get the desired result. I would appreciate any suggestions.

You can do this cross apply to get the minimum date before each order_date and use it in datediff.
SELECT name,CONVERT(VARCHAR(10), order_date, 120) AS order_date, Count(1) [orders],
1+coalesce(datediff(day,t.min_date,od.order_date),0) as [Day]
FROM orders AS od
cross apply (select min(od1.order_date) as min_date
from orders od1
where od.id=od1.id and od.name=od1.name and od1.order_date<od.order_date) t
WHERE id = 73
GROUP BY CONVERT(VARCHAR(10), order_date, 120),name,datediff(day,t.min_date,od.order_date)
ORDER BY order_date,name

Try something like:
SELECT name,
CONVERT(VARCHAR(10), order_date, 120) AS order_date,
Count(1) AS orders,
DATEDIFF(DAY, first_order_date, order_date) + 1
FROM orders AS od
JOIN (SELECT min(order_date) AS first_order_date
FROM orders) as fod ON 1 = 1
WHERE id = 73
GROUP BY CONVERT(VARCHAR(10), order_date, 120),
name,
DATEDIFF(DAY, first_order_date, order_date) + 1
ORDER BY order_date,
name
Hope this will solve your problem

Related

Joining on the same key on the next row

Suppose we have a table which contains customer_id, order_date, and ship_date. A reorder of the product occurs when the same customer's next order_date is within 30 days of the last ship_date.
select * from mytable
customer_id order_date ship_date
1 2017-08-04 2017-08-09
1 2017-09-01 2017-09-05
2 2017-02-02 2017-03-01
2 2017-04-05 2017-04-09
2 2017-04-15 2017-04-19
3 2018-02-02 2018-03-01
Requested: Reorders
customer_id order_date ship_date
1 2017-09-01 2017-09-05
2 2017-04-15 2017-04-19
How can I retrieve only the records for the same customers who had reorders, next order_date within 30
days of the last ship_date.
You can use exists as follows:
Select * from your_table t
Where exists (select 1 from your_table tt
Where tt.customer_id = t.customer_id
And t.ship_date > tt.ship_date
and t.ship_date <= dateadd(day, 30, tt.ship_date))
One method is lead():
select t.customer_id, t.order_date, t.next_ship_date
from (select t.*,
lead(order_date) over (partition by customer_id order by order_date) as next_order_date
lead(ship_date) over (partition by customer_id order by order_date) as next_ship_date
from t
) t
where next_order_date < dateadd(day, 30, ship_date);
EDIT:
If you want the "reorder" row, just use lag():
select t.*
from (select t.*,
lag(ship_date) over (partition by customer_id order by order_date) as prev_ship_date
from t
) t
where prev_ship_date > dateadd(day, 30, order_date);

Aggregate multiple columns based on specific date range with in a month

I need to aggregate Amounts to be displayed by date range per month. To illustrate please take a look at the following table:
Invoice_Payment
Customer_id Invoice_no Invoice_date Amount
---------------------------------------------------
10 10023 2016-07-08 60
10 10018 2016-08-04 90
11 10016 2016-07-01 110
11 10021 2016-07-05 120
12 10028 2016-07-11 10
12 10038 2016-07-31 5
As you'll notice, I want to group them based on Customer_id and display the dates from start to end. Furthermore, this has to be done for each month only.
Following query I have tried so far:
select Customer_id, (mindate + ' to ' + maxdate) Date_Range, Amount
from (
select Customer_id, sum(Amount) Amount, min(Invoice_date) mindate, max(Invoice_date) maxdate
from Invoice_Payment
group by Customer_id
) I ;
From above query I'm getting Output like:
Customer_id Date_Range Amount
10 2016-07-08 to 2016-08-04 150
11 2016-07-01 to 2016-07-05 230
12 2016-07-11 to 2016-07-31 15
Please check this.. SQL Fiddle Working Demo
Let's say Customer_id = 10 who has Invoice_date in July,2016 and August,2016. I need to sum up all payments of that particular Customer for the month of July and August separately within specific date range. But I am getting sum of Amount of all Invoice_date from above endeavor.
Desired output :
Customer_id Date_Range Amount
10 2016-07-08 to 2016-07-08 60
10 2016-08-04 to 2016-08-04 90
11 2016-07-01 to 2016-07-05 230
12 2016-07-11 to 2016-07-31 15
How could I get over this ? Any help would be greatly appreciated.
You are almost done. Just add YEAR and MONTH to GROUP BY.
select Customer_id, (mindate + ' to ' + maxdate) Date_Range, Amount
from (
select Customer_id,
sum(Amount) Amount, min(Invoice_date) mindate, max(Invoice_date) maxdate
from #Invoice_Payment
group by
Customer_id,
YEAR(Invoice_date),
MONTH(Invoice_date)
) I ;
How about grouping by customer_id, month and year
select Customer_id, (mindate + ' to ' + maxdate) Date_Range, Amount
from (
select Customer_id,
sum(Amount) Amount, min(Invoice_date) mindate, max(Invoice_date) maxdate
from #Invoice_Payment
group by Customer_id,month(Invoice_date), year(Invoice_date)
) I
order by customer_id;

Querying average and rolling 12 month average

I want to be able to find out the average per month and rolling average over the last 12 months of a count for the number of changes per customer.
SELECT
crq_requested_by_company as 'Customer',
COUNT(crq_number) as 'Number of Changes'
FROM
change_information ci1
GROUP BY
crq_requested_by_company
At the moment I am just doing the count of the total and my results look like this
crq_requested_by_company count
A 4
B 2
C 2269
D 7696
E 110
F 91
G 33
The date column I will be using is called 'start_date'.
I assume GETDATE() will be needed to work out the rolling average for the last 12 months.
Additional info after comments:
Using the code
;WITH CTE as
(
SELECT
crq_requested_by_company as Customer,
COUNT(crq_number) Nuc,
dateadd(month, datediff(month, 0, crq_start_date),0) m
FROM
change_information ci1
WHERE
crq_start_date >= dateadd(month,datediff(month, 0,getdate()) - 12,0)
GROUP BY
crq_requested_by_company,
datediff(month, 0, crq_start_date)
)
SELECT
Customer,
avg(Nuc) over (partition by Customer order by m) running_avg,
m start_month,
avg(Nuc) over (partition by Customer) simply_average
FROM
CTE
ORDER BY Customer, start_month
This gives the results
Customer running_avg start_month simply_average
A 8 01/01/2016 00:00 13
A 10 01/02/2016 00:00 13
A 10 01/03/2016 00:00 13
A 11 01/04/2016 00:00 13
A 14 01/05/2016 00:00 13
A 13 01/06/2016 00:00 13
B 1 01/01/2016 00:00 1
C 3 01/01/2016 00:00 2
C 3 01/02/2016 00:00 2
C 2 01/03/2016 00:00 2
C 2 01/04/2016 00:00 2
C 2 01/05/2016 00:00 2
C 2 01/06/2016 00:00 2
It needs to look like this so the average of the results above - the average of the 6 months above (I only currently have 6 months of data and needs to be 12 eventually)
Customer avg_of_running_avg
A 11
B 1
C 2
Try this, it should work for sqlserver 2012 using running average:
;WITH CTE as
(
SELECT
crq_requested_by_company as Customer,
COUNT(crq_number) Nuc,
dateadd(month, datediff(month, 0, start_date),0) m
FROM
change_information ci1
WHERE
start_date >= dateadd(month,datediff(month, 0,getdate()) - 12,0)
GROUP BY
crq_requested_by_company,
datediff(month, 0, start_date)
)
SELECT
Customer,
avg(Nuc) over (partition by Customer order by m) running_avg,
m start_month,
avg(Nuc) over (partition by Customer) simply_average
FROM
CTE
ORDER BY Customer, start_month

Calculate discount between weeks

I have a table containing product price data, like that:
ProductId RecordDate Price
46 2015-01-17 14:35:05.533 112.00
47 2015-01-17 14:35:05.533 88.00
45 2015-01-17 14:35:05.533 134.00
I have been able to group data by week and product, with this query:
SET DATEFIRST 1;
SELECT DATEADD(WEEK, DATEDIFF(WEEK, 0, [RecordDate]), 0) AS [Week], ProductId, MIN([Price]) AS [MinimumPrice]
FROM [dbo].[ProductPriceHistory]
GROUP BY DATEADD(WEEK, DATEDIFF(WEEK, 0, [RecordDate]), 0), ProductId
ORDER BY ProductId, [Week]
obtaining this result:
Week Product Price
2015-01-12 00:00:00.000 1 99.00
2015-01-19 00:00:00.000 1 98.00
2015-01-26 00:00:00.000 1 95.00
2015-02-02 00:00:00.000 1 95.00
2015-02-09 00:00:00.000 1 95.00
2015-02-16 00:00:00.000 1 95.00
2015-02-23 00:00:00.000 1 80.00
2015-03-02 00:00:00.000 1 97.00
2015-03-09 00:00:00.000 1 85.00
2015-01-12 00:00:00.000 2 232.00
2015-01-19 00:00:00.000 2 233.00
2015-01-26 00:00:00.000 2 194.00
2015-02-02 00:00:00.000 2 194.00
2015-02-09 00:00:00.000 2 199.00
2015-02-16 00:00:00.000 2 199.00
2015-02-23 00:00:00.000 2 199.00
2015-03-02 00:00:00.000 2 214.00
Now for each product I'd like to get the difference between the last two week values, so that I can calculate the discount. I don't know how to write this as a SQL Query!
EDIT:
Expected output would be something like that:
Product Price
1 -12.00
2 15.00
Thank you!
since you are using Sql Server 2014 you can use LAG or LEAD window function to do this.
Generate Row number to find the last two weeks for each product.
;WITH cte
AS (SELECT *,
Row_number()OVER(partition BY product ORDER BY weeks DESC)rn
FROM Yourtable)
SELECT product,
price
FROM (SELECT product,
Price=price - Lead(price)OVER(partition BY product ORDER BY rn)
FROM cte a
WHERE a.rn <= 2) A
WHERE price IS NOT NULL
SQLFIDDLE DEMO
Traditional solution, can be used before Sql server 2012
;WITH cte
AS (SELECT *,
Row_number()OVER(partition BY product
ORDER BY weeks DESC)rn
FROM Yourtable)
SELECT a.Product,
b.Price - a.Price
FROM cte a
LEFT JOIN cte b
ON a.Product = b.Product
AND a.rn = b.rn + 1
WHERE a.rn <= 2
AND b.Product IS NOT NULL

Add values according to date

I have the following table where I want the Quantity_Sold value to be added for an Item and a Customer if the item has been invoiced more than once in the same month. and I want to get this Sum of Quantity sold per month value in a separate column
Item Customer Invoice_Date Quantity_Sold
A XX 2014-11-04 00:00:00.000 13
A XX 2014-11-21 00:00:00.000 23
A XX 2014-12-19 00:00:00.000 209
A YY 2014-12-01 00:00:00.000 10
A YY 2014-12-22 00:00:00.000 6
B XX 2014-10-29 00:00:00.000 108
B YY 2014-11-06 00:00:00.000 70
B YY 2014-11-24 00:00:00.000 84
EX: XX has invoiced Item A twice in November so I'd want to get 36 (13+23) in a separate column.
So the result table I'd like is,
Item Customer Invoice_date Sum_Qty_Invoiced
A XX 2014-Nov 36
A XX 2014-Dec 209
A YY 2014-Dec 16
B XX 2014-Oct 108
B YY 2014-Nov 154
great if anyone could help me with this
Thanks
This is a simple group by with some string manipulation on the Invoice_Date column.
SELECT
Item,
Customer,
CAST(Year(Invoice_Date) AS VARCHAR(4)) + '-' + LEFT(DateName(m,Invoice_Date),3) AS Invoice_Date,
SUM(Quantity_Sold) AS Sum_Qty_Sold
FROM MyTable
GROUP BY Item,
Customer,
CAST(Year(Invoice_Date) AS VARCHAR(4)) + '-' + LEFT(Datename(m,Invoice_Date),3)
Live example: http://www.sqlfiddle.com/#!6/8fea75/3
You can achieve this by using DatePart and DateName functions of SQL Server.
SELECT Item
, Customer
, CONVERT (CHAR(4), DATEPART(YEAR, Invoice_date)) + '-' + CONVERT(CHAR(3), DATENAME(MONTH, Invoice_date)) AS Invoice_date
, SUM(Quantity_Sold) AS Sum_Qty_Invoiced
FROM [dbo].[Table1]
GROUP BY DATEPART(YEAR, Invoice_date), DATENAME(MONTH, Invoice_date), Item, Customer
Its a simple GroupBy clause. Just add group by on
Item,Customer,CAST(YEAR(Invoice_Date) AS Varchar(4))+'-'+LEFT(DATENAME(m,Invoice_Date),3)
Your query will be something like:
SELECT Item, Customer,
CAST(YEAR(Invoice_Date) AS Varchar(4)) +'-'+
LEFT(DATENAME(m,Invoice_Date),3)
AS Invoice_Date,SUM(Quantity_Sold)
AS Sum_Qty_Invoiced FROM TableName GROUP BY Item,Customer,
Item,Customer,CAST(YEAR(Invoice_Date) AS Varchar(4))+'-
'+LEFT(DATENAME(m,Invoice_Date),3)