Display Top result by region - sql

I have the following table:
Table Orders
OrderID Region CustomerID SalesPersonID
1 North 01 001
2 North 12 002
3 North 33 002
4 North 55 002
5 North 21 001
6 North 11 002
7 North 33 004
8 North 15 002
9 East 23 005
10 East 01 005
11 East 12 005
12 East 33 007
13 East 55 005
14 East 21 006
15 East 11 006
16 East 33 006
17 East 15 007
10 East 34 007
I am looking to display the sales person with most orders in each region. So my end result should look like:
Region SalesPerson Orders
North 002 5
East 005 4
How can I retrieve this information?

You can use window functions - if your database, which you did not tell, supports them:
select Region, SalesPersonID, Orders
from (
select
Region,
SalesPersonID,
count(*) orders,
rank() over(partition by Region order by count(*) desc) rn
from orders
group by Region, SalesPersonID
) t
where rn = 1
rank() allows top ties, if any. You can use row_number() if you want just one result per region, even if there are ties.

Consult the totals by seller and by region.
With the previous totals calculate the maximum sale by region and with this totals the related sellers must be determined
with Totales as
(
select Region,SalesPersonID,count(1) As Totales
from sales
group by Region,SalesPersonID
)
,MaxRegion as
(
select Region,max(Totales) As Totales
from totales
group by Region
)
select MaxRegion.Region,Totales.SalesPersonID,MaxRegion.Totales
from MaxRegion
inner join Totales on MaxRegion.Region=Totales.Region and MaxRegion.Totales=Totales.Totales
Example
Keep in mind that if you have two sellers with the same number of maximum sales, they will be included in the query.

Related

How to aggregate using distinct values across two columns?

I have the following data in an orders table:
revenue expenses location_1 location_2
3 6 London New York
6 11 Paris Toronto
1 8 Houston Sydney
1 4 Chicago Los Angeles
2 5 New York London
7 11 New York Boston
4 6 Toronto Paris
5 11 Toronto New York
1 2 Los Angeles London
0 0 Mexico City London
I would like to create a result set that has 3 columns:
a list of the 10 DISTINCT city names
the sum of revenue for each city
the sum of expenses for each city
The desired result is:
location revenue expenses
London 6 13
New York 17 33
Paris 10 17
Toronto 15 28
Houston 1 8
Sydney 1 8
Chicago 1 4
Los Angeles 2 6
Boston 7 11
Mexico City 0 0
Is it possible to aggregate on distinct values across two columns? If yes, how would I do it?
Here is a fiddle:
http://sqlfiddle.com/#!9/0b1105/1
Shorter (and often faster):
SELECT location, sum(revenue) AS rev, sum(expenses) AS exp
FROM (
SELECT location_1 AS location, revenue, expenses FROM orders
UNION ALL
SELECT location_2 , revenue, expenses FROM orders
) sub
GROUP BY 1;
May be faster:
WITH cte AS (
SELECT location_1, location_2, revenue AS rev, expenses AS exp
FROM orders
)
SELECT location, sum(rev) AS rev, sum(exp) AS exp
FROM (
SELECT location_1 AS location, rev, exp FROM cte
UNION ALL
SELECT location_2 , rev, exp FROM cte
) sub
GROUP BY 1;
The (materialized!) CTE adds overhead, which may outweigh the benefit. Depends on many factors like total table size, available indexes, possible bloat, available RAM, storage speed, Postgres version, ...
fiddle
You could UNION ALL two queries and then select from it...
select location, sum(rev) as rev, sum(exp) as exp
from (
select location_1 as location, sum(revenue) as rev, sum(expenses) as exp
from orders
group by location_1
union all
select location_2 as location, sum(revenue) as rev, sum(expenses) as exp
from orders
group by location_2
)z
group by location
order by 1

Trying to count unique observations in SQL using Partition By

I have these two datasets:
Conditions: I would like to count the number of Unique Discharge_ID as Total_Discharges in my final dataset.
ICU_ID is a little bit more difficult. For PT_ID 001, what is happening is that PT 001 has 4 of the same discharge dates but 4 unique ICU_IDs. Since all of these ICU_IDs occur within 30 days of the Discharge_DT, I only want to count one of them. That is why total discharges for AZ is 1 and ICU_Admits = 1.
For PT_ID 002, I have 2 different Discharge_IDs but 1 ICU Admit that occurred within 30 days of both of the Discharge_IDs. I would like to count the Discharges as 2, and ICU_admits as 1.
DF1: Dataset of Discharges from hospital and admission to ICU within 30 days of Discharge_DT
City
PT_ID
Hospital_ID
Admit_Dt
Discharge_DT
Discharge_ID
ICU_ID
AZ
001
ABC
01-01-2021
01-03-2021
001,ABC,01-01-2021,01-03-2021
001,XYZ,01-05-2021,01-06-2021
AZ
001
ABC
01-01-2021
01-03-2021
001,ABC,01-01-2021,01-03-2021
001,XYZ,01-08-2021,01-09-2021
AZ
001
ABC
01-01-2021
01-03-2021
001,ABC,01-01-2021,01-03-2021
001,XYZ,01-11-2021,01-11-2021
AZ
001
ABC
01-01-2021
01-03-2021
001,ABC,01-01-2021,01-03-2021
001,XYZ,01-15-2021,01-16-2021
CA
002
DEF
04-03-2021
04-07-2021
001,ABC,04-03-2021,04-07-2021
002,LMN,04-27-2021,04-27-2021
CA
002
DEF
04-20-2021
04-21-2021
001,ABC,04-20-2021,04-21-2021
002,LMN,04-27-2021,04-27-2021
DF desired:
City
TotalDischarges
ICU_Admit
AZ
1
1
CA
2
1
Current Code:
DROP TABLE IF EXISTS #edit1
WITH CTE_df1 as (
select * from df1
)
select
City,
PT_ID,
Hospital_ID,
Admit_Dt,
Discharge_DT,
Discharge_ID,
count(ICU_ID) over (partition by ICU_ID) as ICU_Pts,
count(distinct Discharge_ID) as Total_Discharges
into #edit1
from CTE_df1
group by City, Discharge_ID, ICU_ID, PT_ID
order by City,
;with CTE_edit1 as (
select * from #edit1
)
select City, sum(ICU_Pts), sum(Total_Discharges)
from CTE_edit1
group by City
order by City
Current Output: PT_ID 001 works great but PT_ID 002 shows up at 2 in ICU_Admit as it is counting both as unique ICU visits.
City
TotalDischarges
ICU_Admit
AZ
1
1
CA
2
2
Any help would be appreciated

Calculate value using previous and current month

I have below three tables
Stock Table
ID GlobalStock Date Country
1 10 2017/01/01 India
1 20 2017/01/01 India
2 5 2017/02/01 Africa
3 6 2017/08/01 Japan
4 7 2017/04/01 Japan
5 89 2017/08/01 Japan
2 10 2017/03/01 Japan
5 8 2017/03/01 Japan
1 20 2017/02/01 India
ShipFile
ID GlobalStock Date Country
2 10 2017/03/01 Africa
3 60 2017/08/01 India
11 70 2017/08/01 India
1 8 2017/02/01 India
1 9 2017/02/01 India
2 4 2017/03/01 Japan
2 5 2017/04/01 Japan
5 3 2017/03/01 Japan
3 8 2017/08/01 Japan
SalesFiles
ID GlobalStock Date Country
2 10 2017/03/01 India
2 20 2017/03/01 Africa
3 30 2017/08/01 Japan
7 5 2017/02/01 Japan
8 8 2018/01/01 Japan
1 9 2017/02/01 India
1 70 2017/02/01 Africa
13 10 2017/08/01 Japan
10 60 2017/11/01 Japan
I want to calculate -> StockTable(Month - 1) + ShipFile (Month) - Sales (Month)
For example
For ID 1 suppose we are considering Jan (GlobalStock -> 10 + 20) data then in other tables we must take Feb values and country should be same for all tables.
So calculation would be
(10 + 20) + (8 + 9) - (9) = 38
If we consider Feb ID of stocktable then we must consider March data from other tables and so on..
the joining all table i am considering ID and Country.
You can query using subquery or cte as below:
;With cte_Stock as (
Select ID, [Date], Country, sum(GlobalStock) Sum_GlobalStock from Stock
group by Id, [Date], Country
), cte_ShipFiles as (
Select ID, [Date], Country, sum(GlobalStock) Sum_GlobalStock from ShipFile
group by Id, [Date], Country
)
, cte_SalesFiles as (
Select ID, [Date], Country, sum(GlobalStock) Sum_GlobalStock from SalesFiles
group by Id, [Date], Country
)
select s.ID, s.[Date], sf.[Date], s.Country,
YourOutput = s.Sum_GlobalStock+sf.Sum_GlobalStock-sales.Sum_GlobalStock
from cte_Stock s
join cte_ShipFiles sf
on s.ID = sf.ID
and s.Country = sf.Country
and s.[Date] = dateadd(mm,-1, sf.[Date])
join cte_SalesFiles sales
on s.ID = sales.ID
and s.Country = sales.Country
and s.[Date] = dateadd(mm,-1, sales.[Date])
Output as below:
+----+------------+------------+---------+------------+
| ID | Date | Date | Country | YourOutput |
+----+------------+------------+---------+------------+
| 1 | 2017-01-01 | 2017-02-01 | India | 38 |
| 2 | 2017-02-01 | 2017-03-01 | Africa | -5 |
+----+------------+------------+---------+------------+
Here is an approach with derived tables:
DECLARE #CurrentMonth date = '20180101'
DECLARE #NextMonth date = DATEADD(MONTH,1,#CurrentMonth)
SELECT s.Country, SUM(s.GlobalStock) + ShipSum - SaleSum
FROM stock s
LEFT JOIN (SELECT ISNULL(SUM(GlobalStock),0) ShipSum, Country
FROM ShipFile
WHERE Date >= #NextMonth
AND Date <= EOMONTH(#NextMonth)
GROUP BY Country) sh on s.Country = sh.Country
LEFT JOIN (SELECT ISNULL(SUM(GlobalStock),0) SaleSum, Country
FROM SalesFile
WHERE Date >= #NextMonth
AND Date <= EOMONTH(#NextMonth)
GROUP BY Country) sa on s.Country = sa.Country
WHERE s.Date >= #CurrentMonth
AND s.Date <= EOMONTH(#CurrentMonth)
GROUP BY s.Country, ShipSum, SaleSum
Notes:
This uses Country for the joins because ID seems to change between tables.
It also uses a date range assuming that the day portion of your date column is not always the first of the month - if it is always the first that can be simplified to date = #CurrentMonth or date = #NextMonth

How to replace all values in grouped column except first row

I have table like this:
ID Region CreatedDate Value
--------------------------------
1 USA 2016-01-01 5
2 USA 2016-02-02 10
3 Canada 2016-02-02 2
4 USA 2016-02-03 7
5 Canada 2016-03-03 3
6 Canada 2016-03-04 10
7 USA 2016-03-04 1
8 Cuba 2016-01-01 4
I need to sum column Value grouped by Region and CreatedDate by year and month. The result will be
Region Year Month SumOfValue
--------------------------------
USA 2016 1 5
USA 2016 2 17
USA 2016 3 1
Canada 2016 2 2
Canada 2016 3 13
Cuba 2016 1 4
BUT I want to replace all repeated values in column Region with empty string except first met row. The finish result must be:
Region Year Month SumOfValue
--------------------------------
USA 2016 1 5
2016 2 17
2016 3 1
Canada 2016 2 2
2016 3 13
Cuba 2016 1 4
Thank you for a solution. It will be advantage if solution will replace also in column Year
You need to use SUM and GROUP BY to get the SumOfValue. For the formatting, you can use ROW_NUMBER:
WITH Cte AS(
SELECT
Region,
[Year] = YEAR(CreatedDate),
[Month] = MONTH(CreatedDate),
SumOfValue = SUM(Value),
Rn = ROW_NUMBER() OVER(PARTITION BY Region ORDER BY YEAR(CreatedDate), MONTH(CreatedDate))
FROM #tbl
GROUP BY
Region, YEAR(CreatedDate), MONTH(CreatedDate)
)
SELECT
Region = CASE WHEN Rn = 1 THEN c.Region ELSE '' END,
[Year],
[Month],
SumOfValue
FROM Cte c
ORDER BY
c.Region, Rn
ONLINE DEMO
Although this can be done in TSQL, I suggest you do the formatting on the application side.
Query that follows the same order as the OP.

T-SQl Query Problem

I have a table called CorporateTree and Production and the tables have data like:
Table: CorporateTree
DivisionName RegionName CommonName BU
Central Region 1 Raintree 101
Central Region 1 Glenwood 102
East Region 2 Balsa 201
East Region2 Warren 202
Table: Production
ProdID BU ResidentName ResidentID Room
1 101 Smith, Jeff 234859 1002-A
2 202 Mill, Steve 125467 2002-B
3 101 Sisk, Paul 4383943 1009-C
4 101 Sims, Gary 384393 1010-A
5 202 Mason, Sam 32902 1012-A
I am looking to get output like this:
Division Region Facility Business Unit ResidentCount Status
Central Region 1 Glenwood 102 0 Flag
Central Region 1 Raintree 101 3
East Region 2 Balsa 201 0 Flag
East Region 2 Warren 202 2
if the Number of Residents is zero (0) output the value of “Flag” in a Status
i tried this query:
SELECT ct.DivisionName,ct.RegionName,ct.CommonName AS Facility,ct.BU AS [Business Unit],
(SELECT ROW_NUMBER() OVER (PARTITION BY p.BU ORDER BY p.BU DESC)) AS ResidentCount FROM
CorporateTree ct INNER JOIN Production p ON
p.Bu = ct.BU
But it doesn't seem to be working? Can any one help me on this?
You'll want to use a LEFT JOIN to account for any Business Units that have no rows in the Production table.
SELECT ct.DivisionName, ct.RegionName, ct.CommonName AS Facility, ct.BU AS [Business Unit],
COUNT(p.BU) as ResidentCount,
CASE WHEN COUNT(p.BU) = 0 THEN 'Flag' ELSE '' END AS Status
FROM CorporateTree ct
LEFT JOIN Production p
ON p.BU = ct.BU
GROUP BY ct.DivisionName, ct.RegionName, ct.CommonName, ct.BU