SQL to calculate Net Capacity - sql

How to write a SQL to get the Net change in capacity by using the capacity (when status is 1 or 2) and minus the total capacity (when status is 3) for each month? Thanks. Here is the table:
STATUS MONTH CAPACITY
1 01/16 5
3 01/16 2
1 02/16 11
3 02/16 20
1 03/16 8
3 03/16 12
1 04/16 4
2 04/16 10
3 04/16 18
2 05/16 14
3 05/16 37
2 06/16 4
3 06/16 8
For example, the net change in capacity for Jan. 16 is 5 minus 2 equals 3.

You need a conditional sum:
SUM(CASE WHEN STATUS IN (1,2) THEN CAPACITY ELSE 0 END) -
SUM(CASE WHEN STATUS IN (3) THEN CAPACITY ELSE 0 END)

dnoeth answer can be simplified to
SUM(CASE WHEN STATUS IN (1,2) THEN CAPACITY WHEN STATUS IN (3) THEN -CAPACITY ELSE 0 END)

Builds on 1,2 < 3
select MONTH, [Net change]=SUM(CASE STATUS/3 WHEN 0 THEN CAPACITY ELSE -CAPACITY END)
from t
group by MONTH;

no CASE statement:
select month, sum(capacity)-2*sum((status/3)*capacity) from table group by month;
Here is an example

You can join the table to itself and perform the calculation like so:
SELECT
a.status,
a.month,
a.capacity,
b.capacity AS total_capacity,
a.capacity - b.capacity AS net_capacity
FROM
table a
JOIN
table b
ON (a.month = b.month)
AND (b.status = 3)
WHERE
a.status IN (1,2);
-- If you don't want to have the status and instead aggregate in the event there are two within the same month:
SELECT
a.month,
SUM(a.capacity) AS capacity,
SUM(b.capacity) AS total_capacity,
SUM(a.capacity) - MAX(b.capacity) AS net_capacity
FROM
table a
JOIN
table b
ON (a.month = b.month)
AND (b.status = 3)
WHERE
a.status IN (1,2)
GROUP BY
a.month;

SELECT
"Status",
"Month",
SUM(Capacity) AS Capacity
FROM ( SELECT
"Status",
"Month",
CASE WHEN Status = 3 THEN -1 * Capacity ELSE Capacity END AS Capacity FROM tbl
) t
GROUP BY
"Status",
"Month"

Related

How to extract and pivot in sql

I have tables like following
I treid to sum score in pivoted style..
product date score
A 2020/8/1 1
B 2018/8/1 2
B 2018/9/1 1
C 2017/9/1 2
I'd like to transform them to the following pivotedone.
The index is YEAR(t.date) and columns = product
date A B C
2017 0 0 2
2018 0 3 0
2019 0 0 0
2020 1 0 0
Are there any effective way to achieve this?
Thanks
We can handle this by joining a calendar table containing all years of interest to your current table, aggregating by year, and then using conditional aggregation to find the sum of scores for each product.
WITH years AS (
SELECT 2017 AS year FROM dual UNION ALL
SELECT 2018 FROM dual UNION ALL
SELECT 2019 FROM dual UNION ALL
SELECT 2020 FROM dual
)
SELECT
y.year,
SUM(CASE WHEN t.product = 'A' THEN t.score ELSE 0 END) AS A,
SUM(CASE WHEN t.product = 'B' THEN t.score ELSE 0 END) AS B,
SUM(CASE WHEN t.product = 'C' THEN t.score ELSE 0 END) AS C
FROM years y
LEFT JOIN yourTable t
ON y.year = EXTRACT(YEAR FROM t."date")
GROUP BY
y.year
ORDER BY
y.year;
Demo
One option would be using PIVOT Clause after determining the year range, and joining outerly with your data source and setting the null scores as zeroes :
WITH years AS
(SELECT MIN(EXTRACT(year from "date")) AS min_year,
MAX(EXTRACT(year from "date")) AS max_year
FROM tab)
SELECT year, NVL(A,0) AS A, NVL(B,0) AS B, NVL(C,0) AS C
FROM (SELECT l.year, product, SUM(score) AS score
FROM tab t --> your original data source
RIGHT JOIN (SELECT level + min_year - 1 AS year
FROM years
CONNECT BY level BETWEEN 1 AND max_year - min_year + 1) l
ON l.year = EXTRACT(year from "date")
GROUP BY l.year, product)
PIVOT (SUM(score) FOR product IN('A' AS "A", 'B' AS "B", 'C' AS "C"))
ORDER BY year;
YEAR A B C
---- - - -
2017 0 0 2
2018 0 3 0
2019 0 0 0
2020 1 0 0
Demo

Need to count only once in case statement

I need to count only 1 even if condition is met for other records as well
using case statement to check condition
sample data
table a
meeting_id
1
table b
**meeting_id | attendee_id**
1, 10
1, 11
1, 12
1, 13
table c
**attendee_id | dept**
10, field sales
11, field sales
12, dmt
13, field sales
select A.ACC_ID,
TO_NUMBER(SUBSTRING(A.MONTH_NO,1,4)) AS YY,
TO_NUMBER(SUBSTRING(A.MONTH_NO,5,6)) AS MM,
sum(case when USER_INFO.DEPARTMENT='Field Sales' then 1 else 0 end) AS MEETING_WITH_SALE
from "TABLE1" A LEFT JOIN "TABLE2" B
ON (A.meeting_id=A.meeting_id) AND (TO_NUMBER(SUBSTRING(A.MONTH_NO,1,4))=YEAR(A.DATE_OF_MEETING)) AND (TO_NUMBER(SUBSTRING(A.MONTH_NO,5,6))=MONTH(A.DATE_OF_MEETING))
LEFT JOIN "TABLE3" c ON A.attendee_id=c.attendee_id
GROUP BY 1,2
expected result
meeting id 1 has 1 sales meeting because one/more of its attendee's are from sales dept
you have multiple options:
1) get a boolean saying whether the sum was 1 or higher, and convert it to int:
(sum(case when USER_INFO.DEPARTMENT='Field Sales' then 1 else 0 end)>=1)::int)
2) use least function:
least(1,sum(case when USER_INFO.DEPARTMENT='Field Sales' then 1 else 0 end))
3) use another case statement:
case
when sum(case when USER_INFO.DEPARTMENT='Field Sales' then 1 else 0 end)>1
then 1
else 0
end
overall, it's just piping the aggregate that you had into scalar post-processing

Count all rows by status and day

I want to use this table to store tickets in PostgreSQL.
CREATE TABLE TICKET(
ID INTEGER NOT NULL,
TITLE TEXT,
STATUS INTEGER,
LAST_UPDATED DATE,
CREATED DATE
)
;
I use column 'status' to set different status(1, 2, 3, 4). How I can count all tickets by status and day with one SQL query?
I would like to get the final result for example like simple array of numbers:
32 31 23 42 9.11.215
31 21 13 22 10.11.215
3 3 2 43 11.11.215
You can doing it with conditional aggregation, which will unite separate rows into 1 aggregated row :
SELECT t.created,
COUNT(CASE WHEN t.status = '1' THEN 1 END) as cnt_status1,
COUNT(CASE WHEN t.status = '2' THEN 1 END) as cnt_status2,
COUNT(CASE WHEN t.status = '3' THEN 1 END) as cnt_status3,
COUNT(CASE WHEN t.status = '4' THEN 1 END) as cnt_status4
FROM ticket t
GROUP BY t.created

SQL query count (recursive)

I have the following table on my database which contains some transactions for which I need to calc points and rewards.
Every time a TxType A occurs I should record 10 points.
Then I have to subtract from these points the value of the PP column every time a TxType B occurs.
When the calculation goes to zero a reward is reached.
ID TxType PP
1 A 0
2 B 2
3 B 1
4 B 1
5 B 1
6 B 3
7 B 1
8 B 1
9 A 0
10 B 4
11 B 3
12 B 2
13 B 1
14 A 0
15 B 2
I have created the sql query to calc points as follow
SELECT SUM(
CASE
WHEN TxType = 'A' THEN 10
WHEN TxType = 'B' THEN (PP * -1)
END)
FROM myTable
This query return the value of 8, which is exactly the number of points based on the sample data.
How do I calculate the rewards occurred (2 in the given example)?
thanks for helping
One way to do the calculation (in SQL Server 2008) using a correlated subquery:
select t.*,
(select sum(case when TxType = 'A' then 10
when TxType = 'B' then PP * -1
end)
from mytable t2
where t2.id <= t.id
) as TheSum
from mytable t;
You can then apply the logic of what happens when the value is 0. In SQL Server 2012, you could just use a cumulative sum.
To complete Gordon Linoff's the answer, you just need to count the records where TheSum is 0 to get how many rewards occurred:
SELECT COUNT(1)
FROM (
SELECT ID,
TxType,
PP,
( SELECT SUM(CASE TxType WHEN 'A' THEN 10 WHEN 'B' THEN -PP END)
FROM #myTable t2
WHERE t2.id <= t1.id
) AS TheSum
FROM #myTable t1
) Result
WHERE TheSum = 0

JOIN the same table

Hi I have table badge which has columns facility and date (other columns are not important).
I want to select count(*) which should look like this:
DATE | FACILITY 4 COUNT | FACILITY 1 COUNT
12/12/2012 | 234 | 647
I wrote two separate queries for facility 1 and 4 but how to join it to one Query;
SELECT
date,
COUNT(*)
FROM badge
WHERE facility = 3
AND xtype = 19
AND date BETWEEN 'some_date' AND 'some_date'
GROUP BY date
another query differs only in the value of facility.
EDIT: It's informix database.
SELECT date,
SUM(case when facility = 1 then 1 else 0 end) "FACILITY 1 COUNT",
SUM(case when facility = 4 then 1 else 0 end) "FACILITY 4 COUNT"
FROM badge
WHERE (facility = 1 OR facility = 4)
AND xtype = 19
AND date BETWEEN 'some_date' AND 'some_date'
GROUP BY date
give this a try,
SELECT date,
SUM(CASE WHEN facility = 3 THEN 1 ELSE 0 END) `Facility 3 Count`,
SUM(CASE WHEN facility = 1 THEN 1 ELSE 0 END) `Facility 1 Count`
FROM badge
WHERE xtype = 19 AND
date BETWEEN 'some_date' AND 'some_date'
GROUP BY date