Iterate through distinct value with nested sum - sql-server

I'm using MS SQL Server. I have a single table called 'Commissions' that contains customer, date, category, and commission amount. I'm trying to get a customer count by category.
I've figured out the SQL code that gives me a total customer count for a single category.
declare #category nvarchar(50)
set #category = 'Shirts'
select #category , COUNT(*)
from (
SELECT SUM(Commission) AS CommTotal, [Real Customer]
FROM dbo.Commissions
WHERE category = #category and ([Line Item Date] >= CONVERT(DATETIME, '2014-10-01', 102) AND [Line Item Date] < CONVERT(DATETIME, '2015-10-01', 102))
GROUP BY [Real Customer]
) as Agg
The output of this code produces
Shirts 652
What I would like to do next is to do the equivalent of adding a wrapper around this code, that would give me a customer count of all 5 of the categories.
'-- wrapper
select distinct category from commissions
Shirts 652
Pants 1420
Shoes 342
Socks 553
Hats 992
Any suggestions would be appreciated.

First: In your code you are selecting by a single category. In your output example you want all categories. So the selection has to be removed.
Second: I am assuming that the combination of customer and category is not unique but you want a customer only to be counted once per category.
Third: I am copying your date selection.
You need to group by category and then count the number of customers per group counting each customer just once.
Try this:
select category, count(distinct [Real Customer])
from Commissions
where ([Line Item Date] >= CONVERT(DATETIME, '2014-10-01', 102)
and [Line Item Date] < CONVERT(DATETIME, '2015-10-01', 102))
group by Category
Albert

You can use this query. It will count the number of distinct values of [Real Customer] for each category.
SELECT category, COUNT(DISTINCT [Real Customer])
FROM dbo.Commissions
WHERE [Line Item Date] >= CONVERT(DATETIME, '2014-10-01', 102) AND [Line Item Date] < CONVERT(DATETIME, '2015-10-01', 102)
GROUP BY category
You can also optionally add a where clause to limit the number of categories, if you want, to those that you listed. Or leave the query as above to get all categories.

Related

SQL Server query for calculating daily census

I'm having a problem with a query that populates the daily census(# of current inpatients) for a hospital unit. This previous post is where I found the query.
SELECT
[date], COUNT (DISTINCT
CASE WHEN admit_date <= [date] AND discharge_date >= [date] THEN id END)) AS census
FROM
dbo.patients, dbo.census
GROUP BY
[date]
ORDER BY
[date]
There are 2 tables:
dbo.patients with id, admit_date, and discharge_date columns
dbo.census has a date column with every date since 2017, and a census column, which is blank
The query populates the census column, but the census count diminishes toward the end of the dates to smaller numbers then it should. For example, there are 65 null values for discharge_date, so there should be a census count of 65 for today's date, but the query produces a count of 8.
Probably need to account for NULL discharge date
SELECT [date], COUNT (DISTINCT
CASE WHEN admit_date <= [date] AND COALESCE(discharge_date, GETDATE()) >= [date] THEN id END))
AS census
FROM dbo.patients
CROSS JOIN dbo.census
GROUP BY [date]
ORDER BY [date]
That is, assuming [date] is some sort of current date/time stamp. Also, as per Sean Lange's comment, if you really want a CROSS JOIN then you should specify that in the query.

Is there a way to dense_rank() over every row within a date range?

I'm trying to get a count of unique items in a column given an ID number and where the date is within the last 12 months. I need to iterate this over each row in my table.
I am using a combination of dense_rank() and (Over partition by to calculate the count of unique items, but I haven't been able to add in the date filter successfully. The results I see so far are showing count of distinct Unique_Code for each row with the same ID regardless of the date.
select ID,
Unique_Code,
Transaction_Date,
DATEADD(Month, -12, Transaction_Date) as L12M,
dense_rank() over (partition by ID order by Transaction_Date, Unique_Code) as [Unique_Count]
from (select *, (case when datediff(day, lag(Transaction_Date,1,Transaction_Date) over (partition by Unique_Code order by ID), Transaction_Date)
<= 1
then 1 else 2
end) as grp
from datatable1)
I expect the results to show a count of unique items from the unique_code column for the id in the row and where previous entries within the same ID are with the transaction date and the transaction date - 12 months. Right now I am seeing a count of unique items from the unique_code column from each entry with the same ID regardless of the date range.
Unfortunately I do not have your source data to test, however, I've added an extra column to yours below:
select
ID
, Unique_Code
, Transaction_Date
, DATEADD(Month, -12, Transaction_Date) as L12M
, dense_rank() over (partition by ID order by Transaction_Date, Unique_Code) as [Unique_Count]
, rank() over (partition by Transaction_Date order by ID) NewUniqueCount
from (select *, (case when datediff(day, lag(Transaction_Date,1,Transaction_Date) over (partition by Unique_Code order by ID), Transaction_Date) <= 1
then 1 else 2 end) as grp from datatable1)
Let me know if it works? - It should work.

selecting some data within specific number of days

I'm working on sales data and I want to know if Customer A purchased product X from more than one provider within 3 days and I'm working on only one date Claim Date
I Can't find T-Sql query for it
for example
SELECT CusName,ProdName,ProvName
FROM table1
WHERE [Claim Date] between Day([Claim Date]) and DATEADD (Day ,-3 , [Claim Date]
A WHERE EXISTS clause should do the job:
SELECT CusName,ProdName,ProvName
FROM table1 a
WHERE EXISTS (
SELECT 1 FROM table1 b WHERE
b.CusName=a.CusName AND
b.ProdName=a.ProdName AND
b.ProvName!=a.ProvName AND
ABS(DATEDIFF(day,a.ClaimDate,b.ClaimDate))<3
)
You can use the below code for that
SELECT t1.CusName,t1.ProdName,t1.ProvName,t2.ProvName
FROM table t1
JOIN table t2 ON t1.CusName=t2.CusName AND t1.ProdName=t2.ProdName
WHERE t1.ProvName!=t2.ProvName
AND ABS(DATEDIFF(day,t1.ClaimDate,t2.ClaimDate)) = 3
You need a having clause and a count of the providers:
SELECT CusName, COUNT(DISTINCT ProvName) Provider_count
FROM table1
WHERE [Claim Date] between Day([Claim Date]) and DATEADD (Day ,-3 , [Claim Date]
AND ProdName = 'X'
GROUP BY CusName
HAVING COUNT(DISTINCT ProvName) > 1
Note, you do not need to include the count in the select clause, but you do need it in the having clause.

SQL Query for Comparing Customer Order Amounts

I'm looking to create a query that could compare a customer's latest order purchase amount to the previous order amount of the customer's last purchase. Please see example data screenshot below:
Ideally I'd like the query to look for these things in the results:
Total amount from previous order before most recent order date (in this case 9/6/18 would be most recent and 2/2/17 would be the last purchase)
Difference in amount between most recent order and last order amount ($2000-$25 = $1975)
Create a condition in the query to look for customers whose most recent order attempt is 1000 > last purchase amount and the age of the customer's account age is > than 60 days
Note: These conditions for the last bullet could be modified as needed (customer's account age is > 90 days, different in order amount is $500, etc)
Thank you for the assistance!
For 2012 onward you can use LAG
declare #amount decimal(16,2) = 1000
declare #days int = 60
select
*
,TotalWithPrevious = [Order Amount] + lag([Order Amount]) over (partition by UserID order by [Order Date] desc)
,DifferenceofPrevious = [Order Amount] - lag([Order Amount]) over (partition by UserID order by [Order Date] desc)
,CheckCondition = case
when [Order Amount] - lag([Order Amount]) over (partition by UserID order by [Order Date] desc) >= #amount
and datediff(day,[Order Date],lag([Order Date]) over (partition by UserID order by [Order Date] desc)) >= #days
then 'True'
else 'False'
end
from YourTable

T-SQL return top one field based on count of another

I've struggled to search successfully for this as I haven't figured out a search string describing what I want to do, apologies if this has been covered already.
I have a table that contains among others a contract number, a start date, a serial number and a datestamp. These are Many:Many.
What I'm trying to achieve is to return the start date for each individual contract number with the largest number of unique serial numbers and the most recent datestamp, where that start date is valid.
This, as I guess is obvious to T-SQL experts only returns me the one contract number with the largest number of serials. Can anyone tell me what I'm doing wrong?
SELECT TOP (1)
[Contract ID], [Item Begin Date] AS Start_Date,
COUNT([Serial Number]) AS CountSerials,
Datestamp
FROM
SourceTable
GROUP BY
[Contract ID], [Item Begin Date], Datestamp
HAVING
([Item Begin Date] > CONVERT(DATETIME, '1900-01-01 00:00:00', 102))
ORDER BY
CountSerials DESC, Datestamp DESC
Cheers,
Alex
You can put that into a temporary table (without using TOP (1) or oder by):
I changed some table names in the process,
if exists (select * from tempdb.sys.tables where name = '##tmp')
drop table ##tmp
SELECT * into ##tmp
from
(
select
[Contract_ID], [Begin_Date] AS Start_Date,
COUNT([serials]) AS CountSerials,
Datestamp
FROM
SourceTable
GROUP BY
[Contract_ID], [begin_date], Datestamp
HAVING
[begin_date] > CONVERT(DATETIME, '1900-01-01 00:00:00', 102)
) a
select contract_id,Start_Date, max(countserials) as MAXCOUNT, Datestamp from ##tmp
group by contract_id,Start_Date,Datestamp
you can do a subquery with aggregation and extract your desired results from it:
SELECT distinct *
FROM
(
Select
[Contract ID], [Item Begin Date] AS Start_Date,
COUNT([Serial Number]) OVER(PARTITION BY [Contract ID]) AS CountSerials,
datestamp,
MAX(Datestamp) OVER (PARTITION BY [Contract ID]) maxdatestamp
FROM
SourceTable
WHERE
([Item Begin Date] > CONVERT(DATETIME, '1900-01-01 00:00:00', 102))
) x
WHERE
datestamp=maxdatestamp

Resources