T-SQL pivot inventory aging by day range - sql

Writing a T-SQL statement to display items in inventory broken out by day range (pivot).
For example from this inventory table:
ItemName
DateCreated
PO_ID
A
2020-10-07
0
B
2020-10-07
1
A
2020-10-22
2
A
2020-10-22
2
A
2020-10-22
2
B
2020-10-29
3
Would like to generate the bellow results (typically a pivot table), showing the number of pieces per ItemName per day range. The date used to calculate the # of days since DateCreated would be the day the report was ran or passed in as a parameter - in the example shown here, the date used is from '2020-11-07':
ItemName
0-10 days
11-20 days
21-30 days
>30 days
A
0
3
0
1
B
1
0
0
1
Not sure what would be the best way to write the statement to generate the above results?

I would use conditional aggregation:
select itemName,
sum(case when datediff(day, dateCreated, getdate()) <= 10 then 1 else 0 end) as days_0_10,
sum(case when datediff(day, dateCreated, getdate()) > 10 and
datediff(day, dateCreated, getdate()) <= 20
then 1 else 0 end) as days_11_20,
sum(case when datediff(day, dateCreated, getdate()) > 20 and
datediff(day, dateCreated, getdate()) <= 30
then 1 else 0 end) as days_21_30,
sum(case when datediff(day, dateCreated, getdate()) > 30 then 1 else 0 end) as days_31
from t
group by itemName

I would use something similar to the following query SQL Server:
SELECT *
FROM
(
SELECT [ItemName],[PO_ID],
CASE
WHEN DATEDIFF(day, DateCreated, getdate()) BETWEEN 0 AND 10 THEN '0-10 days'
WHEN DATEDIFF(day, DateCreated, getdate()) BETWEEN 11 AND 20 THEN '11-20 days'
WHEN DATEDIFF(day, DateCreated, getdate()) BETWEEN 21 AND 30 THEN '21-30 days'
ELSE '>30 days'
END AS PeriodCreated
FROM [TableName])
) src
pivot
(
COUNT(PO_ID)
FOR PeriodCreated in ([0-10 days], [11-20 days], [>30 days])
) piv

Related

How to count different data on the basis of date for distinct users in SQL Server

I have the following schema :
Table T
|ITEM_ID| |USER_ID| | DUE_DATE |
1 1 2018-01-2
1 1 2018-01-2
1 1 2018-01-3
1 2 2018-01-2
2 1 2018-01-2
2 2 2018-01-2
What I want is to get the count of actions performed by a unique user on that particular day, one week.
This is the select query which I'm using however it does not takes care of the fact about unique user.
select ITEM_ID,
sum(case when cast(due_date as date) = cast(getdate() as date) then 1 else 0 end) as today,
sum(case when cast(due_date as date) >= cast(getdate() - 7 as date) then 1 else 0 end) as week,
sum(case when cast(due_date as date) >= dateadd(month, -1, cast(getdate() as date)) then 1 else 0 end) as month
from t
group by ITEM_ID;
How can I the select count of actions performed by a unique user on that particular day, one week.
For example : let's suppose today is 2018-01-2
So the expected result should be :
ITEM_ID, COUNT_TODAY, COUNT_TOMORROW
1 2 1
2 1 1
What I need is the unique user performing the transaction of that particular item type for that day.
That is in the above example, the user having id 1 performed the transaction of type 1 2 times on 2018-01-2. So it should be counted as 1 instead of 2.
How can I achieve this?
Is this what you want.
select USER_ID, ITEM_ID,
sum(case when cast(due_date as date) = cast(getdate() as date) then 1 else 0 end) as today,
sum(case when cast(due_date as date) >= cast(getdate() - 7 as date) then 1 else 0 end) as week,
sum(case when cast(due_date as date) >= dateadd(month, -1, cast(getdate() as date)) then 1 else 0 end) as month
from t
group by USER_ID, ITEM_ID;

Sum Based on Date

I currently have this code that I want to sum every quantity based on the year. I have written a code that I thought would sum all the charges in 2016 and 2017, but it isn't running correctly.
I added the two different types of partition by statements to test and see if either would work and they don't. When I take them out, the Annual column just shows me the quantity for that specific receipt.
Here is my current code:
SELECT
ReceiptNumber
,Quantity
,Date
,sum(CASE WHEN (Date >= '2016-01-01' and Date < '2017-01-01') THEN
Quantity
ELSE 0 END)
OVER (PARTITION BY Date)
as Annual2016
,sum(CASE WHEN (Date >= '2017-01-01' and Date < '2018-01-01') THEN
Quantity
ELSE 0 END)
OVER (PARTITION BY ReceiptNumber)
as Annual2017
FROM Table1
GROUP BY ReceiptNumber, Quantity, Date
I would like my data to look like this
ReceiptNumber Quantity Date Annual2016 Annual2017
1 5 2016-01-05 17 13
2 11 2017-04-03 17 13
3 12 2016-11-11 17 13
4 2 2017-09-09 17 13
Here is a sample of some of the data I am pulling from:
ReceiptNumber Quantity Date
1 5 2016-01-05
2 11 2017-04-03
3 12 2016-11-11
4 2 2017-09-09
5 96 2015-07-08
6 15 2016-12-12
7 24 2016-04-19
8 31 2017-01-02
9 10 2017-0404
10 18 2015-10-10
11 56 2017-06-02
Try something like this
Select
..
sum(CASE WHEN (Date >= '2016-01-01' and Date < '2017-01-01') THEN
Quantity
ELSE 0 END)
OVER () as Annual2016
sum(CASE WHEN (Date >= '2017-01-01' and Date < '2018-01-01') THEN
Quantity
ELSE 0 END)
OVER ()as Annual2017
..
Where Date >= '2016-01-01' and Date < '2018-01-01'
If you want it printed only once at the top then you should run it in a separate query like:
SELECT YEAR(Date) y, sum(Quantity) s FROM Table1 GROUP BY YEAR(Date)
and then do the main query like this:
SELECT * FROM table1
Easy, peasey ... ;-)
Your original question could also be answered with:
SELECT *,
(SELECT SUM(Quantity) FROM Table1 WHERE YEAR(Date)=2016 ) Annual2016,
(SELECT SUM(Quantity) FROM Table1 WHERE YEAR(Date)=2017 ) Annual2017
FROM table1
You need some conditional aggreation over a Window Aggregate. Simply remove both PARTITION BY as you're already filtering the year in the CASE:
SELECT
ReceiptNumber
,Quantity
,Date
,sum(CASE WHEN (Date >= '2016-01-01' and Date < '2017-01-01') THEN
Quantity
ELSE 0 END)
OVER () as Annual2016
,sum(CASE WHEN (Date >= '2017-01-01' and Date < '2018-01-01') THEN
Quantity
ELSE 0 END)
OVER () as Annual2017
FROM Table1
You probably don't need the final GROUP BY ReceiptNumber, Quantity, Date

SQL - How to count records for each status in one line per day?

I have a table Sales
Sales
--------
id
FormUpdated
TrackingStatus
There are several status e.g. Complete, Incomplete, SaveforLater, ViewRates etc.
I want to have my results in this form for the last 8 days(including today).
Expected Result:
Date Part of FormUpdated, Day of Week, Counts of ViewRates, Counts of Sales(complete), Counts of SaveForLater
--------------------------------------
2015-05-19 Tuesday 3 1 21
2015-05-18 Monday 12 5 10
2015-05-17 Sunday 6 1 8
2015-05-16 Saturday 5 3 7
2015-05-15 Friday 67 5 32
2015-05-14 Thursday 17 0 5
2015-05-13 Wednesday 22 0 9
2015-05-12 Tuesday 19 2 6
Here is my sql query:
select datename(dw, FormUpdated), count(ID), TrackingStatus
from Sales
where FormUpdated <= GETDATE()
AND FormUpdated >= GetDate() - 8
group by datename(dw, FormUpdated), TrackingStatus
order by datename(dw, FormUpdated) desc
I do not know how to make the next step.
Update
I forgot to mention, I only need the Date part of the FormUpdated, not all parts.
You can use SUM(CASE WHEN TrackingStatus = 'SomeTrackingStatus' THEN 1 ELSE 0 END)) to get the status count for each tracking status in individual column. Something like this. SQL Fiddle
select
CONVERT(DATE,FormUpdated) FormUpdated,
DATENAME(dw, CONVERT(DATE,FormUpdated)),
SUM(CASE WHEN TrackingStatus = 'ViewRates' THEN 1 ELSE 0 END) c_ViewRates,
SUM(CASE WHEN TrackingStatus = 'Complete' THEN 1 ELSE 0 END) c_Complete,
SUM(CASE WHEN TrackingStatus = 'SaveforLater' THEN 1 ELSE 0 END) c_SaveforLater
from Sales
where FormUpdated <= GETDATE()
AND FormUpdated >= DATEADD(D,-8,GetDate())
group by CONVERT(DATE,FormUpdated)
order by CONVERT(DATE,FormUpdated) desc
You can also use a PIVOT to achieve this result - you'll just need to complete the list of TrackingStatus names in both the SELECT and the FOR, and no GROUP BY required:
WITH DatesOnly AS
(
SELECT Id, CAST(FormUpdated AS DATE) AS DateOnly, DATENAME(dw, FormUpdated) AS DayOfWeek, TrackingStatus
FROM Sales
)
SELECT DateOnly, DayOfWeek,
-- List of Pivoted Columns
[Complete],[Incomplete], [ViewRates], [SaveforLater]
FROM DatesOnly
PIVOT
(
COUNT(Id)
-- List of Pivoted columns
FOR TrackingStatus IN([Complete],[Incomplete], [ViewRates], [SaveforLater])
) pvt
WHERE DateOnly <= GETDATE() AND DateOnly >= GetDate() - 8
ORDER BY DateOnly DESC
SqlFiddle
Also, I think your ORDER BY is wrong - it should just be the Date, not day of week.

Display data in Days range

I have a sql query output as below
Customer LastModifiedDate
A 1/12/2013
B 1/1/2015
C 1/28/2015
Now I need to display the customers count whose details updated in different days range like (30-60 days), (61-90 Days) and 90+(More than 90 days)
For example please see the output below
DaysRange CustomersCount
30-60 1
61-90 1
90+ 1
Please help me in achieving the above output
Something like this.
SELECT DaysRange=CASE
WHEN Datediff(DAY, LastModifiedDate, Getdate()) BETWEEN 30 AND 60 THEN '30-60'
WHEN Datediff(DAY, LastModifiedDate, Getdate()) BETWEEN 61 AND 90 THEN '61-90'
WHEN Datediff(DAY, LastModifiedDate, Getdate()) > 90 THEN '90+'
END,
CustomersCount=Count(1)
FROM yourtable
GROUP BY CASE
WHEN Datediff(DAY, LastModifiedDate, Getdate()) BETWEEN 30 AND 60 THEN '30-60'
WHEN Datediff(DAY, LastModifiedDate, Getdate()) BETWEEN 61 AND 90 THEN '61-90'
WHEN Datediff(DAY, LastModifiedDate, Getdate()) > 90 THEN '90+'
END
Using this query:
SELECT COUNT(CASE WHEN DATEDIFF(d, LastModifiedDate, getdate()) BETWEEN 30 AND 60 THEN 1 END) AS [30-60],
COUNT(CASE WHEN DATEDIFF(d, LastModifiedDate, getdate()) BETWEEN 61 AND 90 THEN 1 end) AS [61-90],
COUNT(CASE WHEN DATEDIFF(d, LastModifiedDate, getdate()) > 90 THEN 1 END) AS [90+]
FROM mytable
produces the following output:
30-60 61-90 90+
1 1 1
With UNPIVOT we get the desired result set:
SELECT DaysRange, CustomersCount
FROM (
SELECT COUNT(CASE WHEN DATEDIFF(d, LastModifiedDate, getdate()) BETWEEN 30 AND 60 THEN 1 END) AS [30-60],
COUNT(CASE WHEN DATEDIFF(d, LastModifiedDate, getdate()) BETWEEN 61 AND 90 THEN 1 END) AS [61-90],
COUNT(CASE WHEN DATEDIFF(d, LastModifiedDate, getdate()) > 90 THEN 1 END) AS [90+]
FROM mytable) p
UNPIVOT
(CustomersCount FOR DaysRange IN ([30-60], [61-90], [90+])
) AS unpvt;
Output:
DaysRange CustomersCount
30-60 1
61-90 1
90+ 1

Using a sub query in column list

I would like to create a query that would count how many records were created in the last 7, 14 and 28 days. My result would return something like:
7Days 14Days 28Days
21 35 56
I know how to for each timepsan e.g. 7 days, but I do I capture all three in one query?
select count(*) from Mytable
where Created > DATEADD(day,-8, getdate())
Also not pretty, but doesn't rely on subqueries (table/column names are from AdventureWorks). The case statement returns 1 if it falls within your criteria, 0 otherwise - then you just sum the results :
select sum(case when datediff(day, modifieddate, getdate()) <= 7
then 1 else 0 end) as '7days',
sum(case when datediff(day, modifieddate, getdate()) > 7
and datediff(day, modifieddate, getdate()) <= 14
then 1 else 0 end) as '14days',
sum(case when datediff(day, modifieddate, getdate()) > 14
and datediff(day, modifieddate, getdate()) <= 28
then 1 else 0 end) as '28days'
from sales.salesorderdetail
Edit: Updated the datediff function - the way it was written, it would return a negative number (assuming modifieddate was in the past) causing all items to fall under the first case. Thanks to Andriy M for pointing that out
It isn't the prettiest code in the world, but it does the trick. Try selecting from three subqueries, one for each range.
select * from
(select COUNT(*) as Cnt from Log_UrlRewrites where CreateDate >= DATEADD(day, -7, getdate())) as Seven
inner join (select COUNT(*) as Cnt from Log_UrlRewrites where CreateDate >= DATEADD(day, -14, getdate())) as fourteen on 1 = 1
inner join (select COUNT(*) as Cnt from Log_UrlRewrites where CreateDate >= DATEADD(day, -28, getdate())) as twentyeight on 1 = 1
select
(
select count(*)
from Mytable
where Created > DATEADD(day,-8, getdate())
) as [7Days],
(
select count(*)
from Mytable
where Created > DATEADD(day,-15, getdate())
) as [14Days],
(
select count(*)
from Mytable
where Created > DATEADD(day,-29, getdate())
) as [28Days]
SELECT
[7Days] = COUNT(CASE UtmostRange WHEN 7 THEN 1 END),
[14Days] = COUNT(CASE UtmostRange WHEN 14 THEN 1 END),
[28Days] = COUNT(CASE UtmostRange WHEN 28 THEN 1 END)
FROM (
SELECT
*,
UtmostRange = CASE
WHEN Created > DATEADD(day, -8, GETDATE()) THEN 7
WHEN Created > DATEADD(day, -15, GETDATE()) THEN 14
WHEN Created > DATEADD(day, -29, GETDATE()) THEN 28
END
FROM Mytable
) s