sql query to subtract columns - sql

I have a table which looks like this :
Item Month Year Sales
Name1 1 2013 333
Name2 2 2013 454
Name3 1 2013 434
I need to write a stored procedure which looks like this :
Item Sales_On_Month(1) Sales_On_Month(2) Sales_On_Month(2)-Sales_On_Month(1) Sales_On_Month(3) Sales_On_Month(3)-Sales_On_Month(2)
Name1 333 334 1 335 1
Name2 454 454 0 654 200
I tried the following query :
I see a lot of nulls in the middle.If you could let me know the modifications to the query or another approach
it would be great :
select (case when [MONTH] = 1 then Sales END) AS Sales_On_Month(1),
(case when [MONTH] = 2 then Sales END) AS Sales_On_Month(2),
(case when [MONTH] = 2 then Sales END) - (case when [MONTH] = 1 then Sales END) AS Sales_On_Month(2)-Sales_On_Month(1) ...............
from ABC;

Use an aggregate, SUM(), MAX(), whatever, andGROUP BY`:
SELECT Item
,SUM(CASE WHEN [MONTH] = 1 THEN Sales END) AS Sales_1
,SUM(CASE WHEN [MONTH] = 2 THEN Sales END) AS Sales_2
,SUM(CASE WHEN [MONTH] = 2 THEN Sales END) - SUM(CASE WHEN [MONTH] = 1 THEN Sales END) AS Sales_On_Month(2)-Sales_On_Month(1)
FROM ABC
GROUP BY Item

Related

SQL count when equation of two columns are true

I have a sheet with rows (id and year). See below:
id
year
101
2002
101
2006
101
2010
101
2014
101
2018
102
2002
102
2006
102
2010
102
2014
103
2010
I simply want to regroup and reformat my table to look like this:
id
2002
2006
2010
2014
2018
101
1
1
1
1
1
102
1
1
1
1
0
103
0
0
1
0
0
In other words, whenever there is an id with a specific year it will show as a "1" in a field corresponding to that year. Note, that in the sheet there are no other years than the ones above.
I have managed to get the sheet reformatted by
select
id,
null as '2002', null as '2006', null as '2010',
null as '2014', null as '2018'
from
year_sheet
order by
id
But how to count and fill in the values for each year I don't find any solution.
Can someone help?
Thanks
You can use conditional aggregation:
SELECT id
, COUNT(CASE WHEN year = 2002 THEN 1 END) AS "2002"
, COUNT(CASE WHEN year = 2006 THEN 1 END) AS "2006"
, COUNT(CASE WHEN year = 2010 THEN 1 END) AS "2010"
, COUNT(CASE WHEN year = 2014 THEN 1 END) AS "2014"
, COUNT(CASE WHEN year = 2018 THEN 1 END) AS "2018"
FROM t
GROUP BY id
ORDER BY id
SQL Fiddle
try using case statement (Conditional statements)
select id,
case when year=2002 then 1 else 0 end as "2002",
case when year=2006 then 1 else 0 end as "2006",
case when year=2010 then 1 else 0 end as "2010",
case when year=2014 then 1 else 0 end as "2014",
case when year=2018 then 1 else 0 end as "2018"
from table
order by id
assuming that you would like to make the flags as 1 and 0 if the year appears for the id (for every id year appears only once).
In case if you want to count them (for eery id year appears more than once) then try using sum(case when....) as follows
select id,
sum(case when year=2002 then 1 else 0 end)as "2002",
sum(case when year=2006 then 1 else 0 end)as "2006",
sum(case when year=2010 then 1 else 0 end)as "2010",
sum(case when year=2014 then 1 else 0 end)as "2014",
sum(case when year=2018 then 1 else 0 end)as "2018"
from table
group by id
order by id

how to sum two column within single case statement

The query below returns 2 rows, but actually I need only one;
select Datename(month, m.CreatedDate) as [Ay], sum(case when h.Cinsiyet=1 then 1 else 0 end) as [Group1], sum(case when h.Cinsiyet=2 then 1 else 0 end) as [Group2] from Muayene.Muayene m with(nolock)
join Ortak.Hasta h with(nolock) on m.HastaTc = h.HastaTc
group by h.Cinsiyet, Datename(month, m.CreatedDate)
result:
MonthName Group1 Group2
April 4500 0
April 0 9000
Expected Result:
MonthName Group1 Group2
April 4500 9000
I know I can do it wrapping the query with another select statement and Group by month and Sum these results.. But its not efficient and looks dirty code.
How can I make a trick to get expected result without make another sum statement?
FIx the GROUP BY:
select Datename(month, m.CreatedDate) as [Ay],
sum(case when h.Cinsiyet = 1 then 1 else 0 end) as [Group1],
sum(case when h.Cinsiyet = 2 then 1 else 0 end) as [Group2]
from Muayene.Muayene m join
Ortak.Hasta h
on m.HastaTc = h.HastaTc
group by Datename(month, m.CreatedDate);

Counting number of cases within a case

I'm looking to count the number of people who spent a certain amount at a certain store in a certain year.
I tried making a nested CASE expression, the first that looks at transactions at a certain year, the second looking at the sum of a person's transaction to a certain store, but Oracle didn't like nested CASE expressions (unless I was doing it wrong).
From this SQL example:
CREATE TABLE table_name ( PersonId, StoreId, AmountSpent, Year) as
select 1, 1, 60, 2017 from dual union
select 1, 1, 50, 2017 from dual union
select 1, 2, 70, 2018 from dual union
select 2, 1, 10, 2017 from dual union
select 2, 1, 10, 2017 from dual union
select 2, 1, 200, 2018 from dual union
select 2, 2, 60, 2018 from dual union
select 2, 2, 60, 2018 from dual union
select 3, 1, 25, 2017 from dual union
select 3, 2, 200, 2017 from dual union
select 3, 2, 200, 2018 from dual;
Select
StoreId,
SUM(CASE WHEN Year = '2017'
THEN AmountSpent
ELSE 0
End) Year17,
SUM(CASE WHEN Year = '2018'
THEN AmountSpent
ELSE 0
End) Year18
FROM table_name
GROUP BY StoreId;
STOREID YEAR17 YEAR18
---------- ---------- ----------
1 145 200
2 200 330
Would someone be able to make an output like this? I think some numbers might be wrong, but it seems like most of the people get the gist of where I'm going.
+----+---------+------------+---------------------+-------------------+---------------------+---------------------+------------+-------------------+---------------------+
| | STOREID | Y17_INCOME | Y17_SPENT_BELOW_100 | Y17_SPENT_100_150 | Y17_SPENT_ABOVE_150 | Y18_INCOME | Y18_SPENT_BELOW_100 | Y18_SPENT_100_150 | Y18_SPENT_ABOVE_150 |
+----+---------+------------+---------------------+-------------------+---------------------+------------+---------------------+-------------------+---------------------+
| 1 | 1 | 145 | 2 | 1 | 0 | 200 | 2 | 0 | 1 |
+----+---------+------------+---------------------+-------------------+---------------------+---------------------+------------+-------------------+---------------------+
| 2 | 2 | 200 | 0 | 0 | 1 | 330 | 0 | 0 | 1 |
+----+---------+------------+---------------------+-------------------+---------------------+------------+---------------------+-------------------+---------------------+
Not sure if this is possible, but it would be great if so!
I don't think your data matches your expected output.
You need a subquery where you sum spendings of each person yearly for each store ( grouping by store & person). Then you will need to group only by store and use sum to retrieve income for given year. count + case + distinct is the key to count unique person ids that have spent money and assign them to amount spending group (one of three columns for each year).
Notice that yearXX_spending column already holds sum of amount spent by a person for a given store and year (and this is coming from subquery):
select
storeid
, sum(year17_spending) as y17_income
, count(distinct case when year17_spending < 100 then personid end) as y17_spent_below_100
, count(distinct case when year17_spending between 100 and 150 then personid end) as y17_spent_100_150
, count(distinct case when year17_spending > 150 then personid end) as y17_spent_above_150
, sum(year18_spending) as y18_income
, count(distinct case when year18_spending < 100 then personid end) as y18_spent_below_100
, count(distinct case when year18_spending between 100 and 150 then personid end) as y18_spent_100_150
, count(distinct case when year18_spending > 150 then personid end) as y18_spent_above_150
from (
select
storeid
, personid
, sum(case when year = 2017 then amountspent end) as year17_spending
, sum(case when year = 2018 then amountspent end) as year18_spending
from table_name
group by storeid, personid
) t
group by storeid
Output for your sample data:
+----+---------+------------+---------------------+-------------------+---------------------+---------------------+------------+-------------------+---------------------+
| | STOREID | Y17_INCOME | Y17_SPENT_BELOW_100 | Y17_SPENT_100_150 | Y17_SPENT_ABOVE_150 | Y18_INCOME | Y18_SPENT_BELOW_100 | Y18_SPENT_100_150 | Y18_SPENT_ABOVE_150 |
+----+---------+------------+---------------------+-------------------+---------------------+------------+---------------------+-------------------+---------------------+
| 1 | 1 | 145 | 2 | 1 | 0 | 200 | 2 | 0 | 1 |
+----+---------+------------+---------------------+-------------------+---------------------+---------------------+------------+-------------------+---------------------+
| 2 | 2 | 200 | 0 | 0 | 1 | 330 | 0 | 0 | 1 |
+----+---------+------------+---------------------+-------------------+---------------------+------------+---------------------+-------------------+---------------------+
Also note that by doing UNION when you are building sample data, you're getting rid of duplicates so that line:
select 2, 1, 10, 2017
goes to the table only once (not twice). If you mean to include everything without removing duplicates, use UNION ALL instead.
You can do store/person totals in an inline view, which on its own produces:
SELECT
StoreId,
PersonId,
Year,
SUM(AmountSpent) AS TotalSpent
FROM table_name
GROUP BY
StoreId,
PersonId,
Year
ORDER BY
StoreId,
Year,
PersonId;
STOREID PERSONID YEAR TOTALSPENT
---------- ---------- ---------- ----------
1 1 2017 110
1 2 2017 10
1 3 2017 25
1 2 2018 200
2 3 2017 200
2 1 2018 70
2 2 2018 60
2 3 2018 200
and then use multiple separate case expressions and aggregates in an outer query:
SELECT
StoreId,
SUM(CASE WHEN Year = '2017'
THEN TotalSpent
ELSE 0
END) Year17,
COUNT(CASE WHEN Year = '2017'
AND TotalSpent < 100
THEN TotalSpent
END) AS Year17lt100,
COUNT(CASE WHEN Year = '2017'
AND TotalSpent >= 100
AND TotalSpent < 150
THEN TotalSpent
END) AS Year17gte100lt150,
COUNT(CASE WHEN Year = '2017'
AND TotalSpent >= 150
THEN TotalSpent
END) AS Year17gte150,
SUM(CASE WHEN Year = '2018'
THEN TotalSpent
ELSE 0
END) Year18,
COUNT(CASE WHEN Year = '2018'
AND TotalSpent < 100
THEN TotalSpent
END) AS Year18lt100,
COUNT(CASE WHEN Year = '2018'
AND TotalSpent >= 100
AND TotalSpent < 150
THEN TotalSpent
END) AS Year18gte100lt150,
COUNT(CASE WHEN Year = '2017'
AND TotalSpent >= 150
THEN TotalSpent
END) AS Year18gte150
FROM (
SELECT
StoreId,
PersonId,
Year,
SUM(AmountSpent) AS TotalSpent
FROM table_name
GROUP BY
StoreId,
PersonId,
Year
)
GROUP BY StoreId
ORDER BY StoreId;
which gets:
STOREID YEAR17 YEAR17LT100 YEAR17GTE100LT150 YEAR17GTE150 YEAR18 YEAR18LT100 YEAR18GTE100LT150 YEAR18GTE150
---------- ---------- ----------- ----------------- ------------ ---------- ----------- ----------------- ------------
1 145 2 1 0 200 0 0 0
2 200 0 0 1 330 2 0 1
That doesn't match the output in your image, but I think that's wrong...
I've also changed the buckets slightly from what your column headings suggested, but you can tweak those if you do really want what you showed.
You could also reduce the code and repetition by using a pivot() clause, if you're on a version of Oracle which supports that; which can provide multiple outputs and allows conditional aggregation too:
SELECT *
FROM (
SELECT
StoreId,
Year,
SUM(AmountSpent) AS TotalSpent
FROM table_name
GROUP BY
StoreId,
PersonId,
Year
)
PIVOT (
SUM(TotalSpent) as total,
COUNT(CASE WHEN TotalSpent < 100 THEN TotalSpent END) as lt100,
COUNT(CASE WHEN TotalSpent >= 100 AND TotalSpent < 150 THEN TotalSpent END) as gte100lt150,
COUNT(CASE WHEN TotalSpent >= 150 THEN TotalSpent END) as gte150
FOR Year IN (2017 as year17, 2018 as year18)
)
ORDER BY StoreId;
STOREID YEAR17_TOTAL YEAR17_LT100 YEAR17_GTE100LT150 YEAR17_GTE150 YEAR18_TOTAL YEAR18_LT100 YEAR18_GTE100LT150 YEAR18_GTE150
---------- ------------ ------------ ------------------ ------------- ------------ ------------ ------------------ -------------
1 145 2 1 0 200 0 0 1
2 200 0 0 1 330 2 0 1
Oracle will expand that under the hood to look like the original longer query above, but it's easier to maintain.
Updated SQL Fiddle.

Group by datepart and find total count of individual values of each record

This is table structure;
ID Score Valid CreatedDate
1 A 1 2018-02-19 23:33:10.297
2 C 0 2018-02-19 23:32:40.700
3 B 1 2018-02-19 23:32:30.247
4 A 1 2018-02-19 23:31:37.153
5 B 0 2018-02-19 23:25:08.667
...
I need to find total number of each score and valid in each month
I mean final result should be like
Month A B C D E Valid(1) NotValid(0)
January 123 343 1021 98 12 1287 480
February 516 421 321 441 421 987 672
...
This is what I tried;
SELECT DATEPART(year, CreatedDate) as Ay,
(select count(*) from TableResults where Score='A') as 'A',
(select count(*) from TableResults where Score='B') as 'B',
...
FROM TableResults
group by DATEPART(MONTH, CreatedDate)
but couldn't figure how to calculate all occurrence of scores on each month.
Use conditional aggregation.
SELECT DATEPART(year, CreatedDate) as YR
, DATEPART(month, CreatedDate) MO
, sum(Case when score = 'A' then 1 else 0 end) as A
, sum(Case when score = 'B' then 1 else 0 end) as B
, sum(Case when score = 'C' then 1 else 0 end) as C
, sum(Case when score = 'D' then 1 else 0 end) as D
, sum(Case when score = 'E' then 1 else 0 end) as E
, sum(case when valid = 1 then 1 else 0 end) as Valid
, sum(case when valid = 0 then 1 else 0 end) as NotValid
FROM TableResults
GROUP BY DATEPART(MONTH, CreatedDate), DATEPART(year, CreatedDate)
I'm not a big fan of queries in the select; I find they tend to cause performance problems in the long run. Since we're aggregating here I just applied the conditional logic to all the columns.

SQL query to calculate total per month as a column

I am stuck on a SQL query. I am using PostgreSQL. I need to get the total for each month for all states.
table A
--------------------------------------------------------
created | Name | Agent_id | Total
--------------------------------------------------------
3/14/2013 | Harun | 1A | 5
3/14/2013 | Hardi | 2A | 20
4/14/2013 | Nizar | 3A | 30
5/14/2013 | moyes | 4A | 20
table B
----------------------------
Agent_id| state_id
----------------------------
1A | 1
2A | 1
3A | 1
4A | 2
table C
----------------------------
state_id | State
----------------------------
1 | Jakarta
2 | Singapore
3 | Kuala lumpur
DESIRED RESULT:
-----------------------------------------------------------------------------------------------
No |State | Januari | February | March | April | Mei ... December| Total
-----------------------------------------------------------------------------------------------
1 |Jakarta |0 |0 |25 | 30 | 0 ... | 55
2 |Singapore |0 |0 | 0 | 0 | 20 ... | 20
3 |Kuala Lumpur |0 |0 | 0 | 0 | 0 ... | 0
to have all state with no data in table A / B you have to use OUTER JOIN
to complete #bma answer
select
no,
state,
sum(case when month = 1 then total else 0 end) as januari,
sum(case when month = 2 then total else 0 end) as februari,
sum(case when month = 3 then total else 0 end) as mars,
sum(case when month = 4 then total else 0 end) as april,
sum(case when month = 5 then total else 0 end) as may,
sum(case when month = 6 then total else 0 end) as juni,
sum(case when month = 7 then total else 0 end) as juli,
sum(case when month = 8 then total else 0 end) as august,
sum(case when month = 9 then total else 0 end) as september,
sum(case when month = 10 then total else 0 end) as october,
sum(case when month = 11 then total else 0 end) as november,
sum(case when month = 12 then total else 0 end) as december,
sum(coalesce(total,0)) as total
from (
select
c.state_id as no,
extract(month from created) as month,
state,
sum(total) as total
from tablec c
left join tableb b on ( b.state_id = c.state_id)
left join tablea a on ( a.agent_id = b.agent_id)
group by c.state_id,state,month
) sales
group by no,state;
SQL Fiddle demo
Actually i do not know much about postgres sql this is a try see if this works
try this
Select EXTRACT(MONTH FROM TIMESTAMP table A.created) ,
table C.State , SUM(Total) From table A , table B , table C
Where table A.Agent_id = table B.Agent_id
And table B.state_id = table C.state_id
Group by table C.State , EXTRACT(MONTH FROM TIMESTAMP table A.created);
Something like the following should give you results like your sample results. I'm not sure what the "No" column was though. This query is untested.
select state,
sum(case when mm = 1 then total else 0 end) as jan,
sum(case when mm = 2 then total else 0 end) as feb,
sum(case when mm = 3 then total else 0 end) as mar,
sum(case when mm = 4 then total else 0 end) as apr,
sum(case when mm = 5 then total else 0 end) as may,
sum(case when mm = 6 then total else 0 end) as jun,
sum(case when mm = 7 then total else 0 end) as jul,
sum(case when mm = 8 then total else 0 end) as aug,
sum(case when mm = 9 then total else 0 end) as sep,
sum(case when mm = 10 then total else 0 end) as oct,
sum(case when mm = 11 then total else 0 end) as nov,
sum(case when mm = 12 then total else 0 end) as dec,
sum(total) as total
from (
select extract(month from created) as mm,
state,
sum(total) as total
from table_a
group by state,mm
) s
group by state;