I have the following table:
CREATE TABLE tablename ("ID" varchar2(1), "Type" varchar2(3), "Value" int);
INSERT ALL
INTO tablename ("ID", "Type", "Value")
VALUES ('A', 'MS',2)
INTO tablename ("ID","Type", "Value")
VALUES ('A', 'MS', 5)
INTO tablename ("ID", "Type", "Value")
VALUES ('A', 'MSH', 6)
INTO tablename ("ID", "Type", "Value")
VALUES ('A', 'MSH', 10)
INTO tablename ("ID", "Type", "Value")
VALUES ('A', 'MSO', -5)
INTO tablename ("ID", "Type", "Value")
VALUES ('A', 'MSO', 12)
INTO tablename ("ID", "Type", "Value")
VALUES ('B', 'MS',5)
INTO tablename ("ID","Type", "Value")
VALUES ('B', 'MS', -4)
INTO tablename ("ID", "Type", "Value")
VALUES ('B', 'MSH', 2)
INTO tablename ("ID", "Type", "Value")
VALUES ('B', 'MSH', 11)
INTO tablename ("ID", "Type", "Value")
VALUES ('B', 'MSO', -5)
INTO tablename ("ID", "Type", "Value")
VALUES ('B', 'MSO', 13)
SELECT * FROM dual
;
The table will be grouped by ID and Type and use the sum of the Values. Now I want to get the difference of MS-MSH and MS-MSO for each ID.
So the result should be something like
ID | Type | sum(value) | Dif
A | MS | 7 | 0
A | MSH | 16 | -9
A | MSO | 7 | 0
B | MS | 1 | 0
B | MH | 13 | -12
B | MSO | 9 | -8
Here is the table to work with
(More of a comment) I've not tested, i'd try something along these lines. Hope this is of some help. Aologies, i haven't tested.
with cte as
(
select t.id,t.type,sum(t.value) as sumval
from
tablename as t
group by t.id,t.type
)
select c.*,
case c.type
when 'ms' then 0
else (c.sumval-(select c2.sumval from cte c2 where c2.id=c.id and c2.type='ms'))
end dif
from cte c
order by c.id,c.type
Query works if u have "Types"
like 'MS1', 'MSH1', 'MSO1', 'MS2', 'MSO2'...
, diff is partitioned by "ID"
and the number on end of the "Type"
string, query does only 1 look at the table no sub-querys and cte, no case statement.
QUERY:
select "ID","Type",sum("Value") Sum_value,
FIRST_VALUE (sum("Value")) over (partition by "ID",
nvl(regexp_substr("Type",'[0-9]{1,}$'),'0')
ORDER BY "ID")-sum("Value")
diff
from tablename
group by ("ID","Type")
SAMPLE DATA:
CREATE TABLE tablename ("ID" varchar2(1), "Type" varchar2(3), "Value" int);
INSERT ALL
INTO tablename ("ID", "Type", "Value")
VALUES ('A', 'MS',2)
INTO tablename ("ID","Type", "Value")
VALUES ('A', 'MS', 5)
INTO tablename ("ID", "Type", "Value")
VALUES ('A', 'MSH', 6)
INTO tablename ("ID", "Type", "Value")
VALUES ('A', 'MSH', 10)
INTO tablename ("ID", "Type", "Value")
VALUES ('A', 'MSO', -5)
INTO tablename ("ID", "Type", "Value")
VALUES ('A', 'MSO', 12)
INTO tablename ("ID", "Type", "Value")
VALUES ('B', 'MS',5)
INTO tablename ("ID","Type", "Value")
VALUES ('B', 'MS', -4)
INTO tablename ("ID", "Type", "Value")
VALUES ('B', 'MSH', 2)
INTO tablename ("ID", "Type", "Value")
VALUES ('B', 'MSH', 11)
INTO tablename ("ID", "Type", "Value")
VALUES ('B', 'MSO', -5)
INTO tablename ("ID", "Type", "Value")
VALUES ('B', 'MSO', 13)
SELECT * FROM dual
;
RESULT:
ID Type SUM_VALUE DIFF
----------------------
A MS 7 0
A MSH 16 -9
A MSO 7 0
B MS 1 0
B MSH 13 -12
B MSO 8 -7
You can wrap the aggregation functions in an analytic function and use conditional aggregation to find the MS
value for type
with the same id
(then you only read the table once and do not need any correlated sub-queries or CTEs):
SELECT id,
type,
sum(value) as sumval,
MAX(CASE type WHEN 'MS' THEN SUM(value) END) OVER (PARTITION BY id)
- SUM(value) AS diff
FROM tablename
GROUP BY
id,
type;
Which, for the sample data:
CREATE TABLE tablename (ID, Type, Value) AS
SELECT 'A', 'MS', 2 FROM DUAL UNION ALL
SELECT 'A', 'MS', 5 FROM DUAL UNION ALL
SELECT 'A', 'MSH', 6 FROM DUAL UNION ALL
SELECT 'A', 'MSH', 10 FROM DUAL UNION ALL
SELECT 'A', 'MSO', -5 FROM DUAL UNION ALL
SELECT 'A', 'MSO', 12 FROM DUAL UNION ALL
SELECT 'B', 'MS', 5 FROM DUAL UNION ALL
SELECT 'B', 'MS', -4 FROM DUAL UNION ALL
SELECT 'B', 'MSH', 2 FROM DUAL UNION ALL
SELECT 'B', 'MSH', 11 FROM DUAL UNION ALL
SELECT 'B', 'MSO', -5 FROM DUAL UNION ALL
SELECT 'B', 'MSO', 13 FROM DUAL;
Outputs:
ID TYPE SUMVAL DIFF A MS 7 0 A MSH 16 -9 A MSO 7 0 B MS 1 0 B MSH 13 -12 B MSO 8 -7
db<>fiddle here
With the LAG
analytic function:
SQL> with temp as
2 (select id, type, sum(value) sumval
3 from tablename
4 group by id, type
5 )
6 select id, type, sumval,
7 --
8 -case when type = 'MS' then 0
9 when type = 'MSH' then sumval - lag(sumval, 1) over (partition by id order by type)
10 when type = 'MSO' then sumval - lag(sumval, 2) over (partition by id order by type)
11 end diff
12 from temp
13 order by id, type;
ID TYPE SUMVAL DIFF
-- ---- ---------- ----------
A MS 7 0
A MSH 16 -9
A MSO 7 0
B MS 1 0
B MSH 13 -12
B MSO 8 -7
6 rows selected.
SQL>
Not related to your problem, but - this is Oracle. Avoid double quotes and mixed case identifiers, you'll only have problems with these.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.