Calculate value using previous and current month - sql

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

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

calculating urban population percentage of total population for each district in PostgreSql

I have a table namely settlement consist of 3 columns and 5437 rows.
The first column has 8 group(A,B,C,D,E,F,G,H) and the second one has '6' group(City,Town,Village,Island,Suburb,Hamlet)
My table is as following...
ID district_name Cluster Population
1003 A village 1543
1002 B town 63437
1003 C village 1698
1002 D town 11785
1040 E hamlet 100
2034 F hamlet 190
4003 G city 207561
4243 H Suburb 682
674 D Island 718
1012 A village 1566
1040 F hamlet 200
1020 D town 11881
4055 D city 208763
I want to calculate the percentage of population for each district base on the following condition;
total population in each district/sum(population)*100
where cluster='city' or cluster='town'
A practical example of my desire outpout can be as follows,
district_name Population_total(City+Town+island) Urban_Percentage(Town_City)
D 233147 99.69(232429/233147 * 100)
SQL DEMO
WITH district as (
SELECT district_name,
sum("Population") as district_total
FROM residentioal
where "Cluster"='city' or "Cluster"='town'
GROUP BY district_name
), whole_total as (
SELECT district_name, sum("Population") as total
FROM residentioal
GROUP BY district_name
)
SELECT d.district_name,
total as whole_total,
district_total as city_town_total,
district_total * 100.0 / total as PP
FROM district d
JOIN whole_total w
ON d.district_name = w.district_name
OUTPUT
| district_name | whole_total | city_town_total | pp |
|---------------|-------------|-----------------|-------------------|
| D | 233147 | 232429 | 99.69203978605772 |
| B | 63437 | 63437 | 100 |
| G | 207561 | 207561 | 100 |
EDIT:
SQL DEMO
You actually can do it with a single query:
SELECT district_name,
sum("Population") as total,
sum(CASE WHEN "Cluster" IN ('city', 'town')
THEN "Population"
ELSE 0
END ) as district_total,
sum(CASE WHEN "Cluster" IN ('city', 'town')
THEN "Population"
ELSE 0
END ) * 100.0 / sum("Population") as PP
FROM residentioal
GROUP BY district_name;

SQL Server: group by, coalesce and select one of coalesce'd

I have a table called Regions:
city district1 district2 district3 district4
---------------------------------------------------------
Michigan 2 NULL NULL 2
Michigan 2 20 NULL 20
Michigan 2 NULL 3 3
Ontario 3 NULL NULL 3
Quebec 4 1 NULL 1
Quebec 4 NULL NULL 4
Edmonton NULL 7 NULL 7
Edmonton NULL NULL 11 11
district4 is (coalesce(district3, district2, district1))
And I'd like to get a distinct grouped by City also with district1
city district1 district_final
--------------------------------------
Michigan 2 3
Ontario 3 3
Quebec 4 1
Edmonton NULL 11
district_final is not max; it's coalesce of group
select distinct r1.city, r1.district1, coalesce(r3.district3, r2.district2, r1.district1) district_final
from Regions r1
left outer join Regions r2 on r1.city = r2.city and r2.district2 is not null
left outer join Regions r3 on r1.city = r3.city and r3.district3 is not null
Following code should solve the purpose i guess:
SELECT CITY,dct1 as district1,MAX(DCT) as district_final FROM
(
SELECT CITY, district1 as dct1, district1 AS DCT FROM [TABLE]
UNION
SELECT CITY, district1 as dct1, district2 AS DCT FROM [TABLE]
UNION
SELECT CITY, district1 as dct1, district3 AS DCT FROM [TABLE]
) tempTable
group by CITY,dct1;

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.

using Pivot in SQL Query

I have the following table structure also I have mention my expected output please help me with query
As per My previous question
Get count for multiple fields using group by in SQL
i am getting output as follows using below query
select data.category, cl.combovalue as esilocation, cd.combovalue as esidispensary,
year(date) as year, month(date) as month,
sum(data.joins) as [Joining Count], sum(data.terms) as [Termination Count]
from (
select category, esilocation, esidispensary, dateofjoining as date,
1 as joins, 0 as terms
from dbo.employeedetail
where dateofjoining is not null
union all
select category, esilocation, esidispensary, terminationdate as date,
0 as joins, 1 as terms
from dbo.employeedetail
where terminationdate is not null
) data
left join dbo.combovalues cl on cl.id = data.esilocation
left join dbo.combovalues cd on cd.id = data.esidispensary
where category in ( 1, 2 )
and date >= '2014-01-01'
and date <= '2014-12-31'
group by data.category, cl.combovalue, cd.combovalue, year(date), month(date)
Query output :
category esilocation esidispensary year month Joining Count Termination Count
1 mumbai mumbai 2014 8 1 0
1 mumbai mumbai 2014 11 0 1
1 pune mumbai 2014 6 1 0
1 pune mumbai 2014 8 1 1
2 pune mumbai 2014 10 1 0
2 pune mumbai 2014 11 0 1
2 pune pune 2014 9 2 0
2 pune pune 2014 11 0 2
But problem is i want Pivot of this above table i.e
Expected Output
category esilocation esidispensary 8/2014 join 8/2014 term 11/2014 join 11/2014 term
1 mumbai mumbai 1 0 0 1
1 pune mumbai 1 1 null null
2 pune mumbai null null 0 1
2 pune pune null null 0 2