I have a table (MyTable) with this columns:
point
alarm
load_id
countAlarms
...
and I use this query:
select point, decode(alarm,0,'new','rec') NewRec, sum (countAlarms) total_alarms, load_id from MyTable
where 1=1
--and load_id = (select max(load_id) from MyTable ) -0
group by point, decode(alarm,0,'new','rec'), load_id
order by 1, 2
)
to receive something like this:
point1 new 1200 111113
point1 rec 6000 111113
point2 new 1220 111113
point2 rec 3000 111113
point3 new 3220 111113
point3 rec 1000 111113
point1 new 1300 111112
point1 rec 6300 111112
point3 new 1220 111112
point3 rec 1100 111112
point1 new 1300 111111
point1 rec 6300 111111
point2 new 1120 111111
point2 rec 3100 111111
point3 new 1220 111111
point3 rec 1100 111111
....
what i need is this:
point newRec point point point
---------------------------------------
point1 new 1200 1300 1300
point1 rec 6000 6300 6300
point2 new 1220 1120
point2 rec 3000 3100
point3 new 3220 1220 1220
point3 rec 1000 1100 1100
I have tried with a full outer join but it don't work :(
It looks like you want to pivot your result set, rather than join it to itself. Assuming you're on Oracle 11g or higher you can do this natively:
select * from (
select point, decode(alarm,0,'new','rec') NewRec, countAlarms, load_id
from MyTable
)
pivot (
sum(countAlarms) as alarms
for (load_id) in (111113 as a, 111112 as b, 111111 as c)
)
order by 1, 2;
Which with sample data matching your output above gives:
POINT NEWREC A_ALARMS B_ALARMS C_ALARMS
------ ------ ---------- ---------- ----------
point1 new 1200 1300 1300
point1 rec 6000 6300 6300
point2 new 1220 1120
point2 rec 3000 3100
point3 new 3220 1220 1220
point3 rec 1000 1100 1100
SQL Fiddle demo.
You have to know the values you're pivoting on though; it isn't clear if you know the load IDs in advance, but the commented-out load ID filter in your original query suggests you might not. If you always want the three (or any fixed number of) highest load IDs then that can be achieved by modifying the inner query and the pivot criteria, e.g. with an analytic dense_rank() pseudo-column:
select * from (
select point, decode(alarm,0,'new','rec') NewRec, countAlarms,
dense_rank() over (partition by null order by load_id desc) as rnk
from MyTable
)
pivot (
sum(countAlarms) as alarms
for (rnk) in (1 as a, 2 as b, 3 as c)
)
order by 1, 2;
SQL Fiddle.
Related
We have this data : Table R(A,..) with attribute A, nbLine of R is 1000, distinct value for A are 500.
data are displayed like this : bucket -> end_point_value.
1 -> 800
2 -> 900
3 -> 1000
4 -> 1200
5 -> 1500
6 -> 2000
7 -> 2300
8 -> 2400
9 -> 2550
10 -> 2590
the question is : Does this histogram confirm or deny the hypothesis of a uniform distribution uniform?
I think I can not confirm nor deny, what do you think ?
First you must ask, which histogram type is defined on the column.
Oracle provides four different histogram types and is you want to claim about uniform distribution the frequency histogram must be defined.
The frequency histogram has one bucket for each distinct value (stored in ENDPOINT_VALUE and the frequency is (additive) stored in the column ENDPOINT_NUMBER)
So if you histogram has only 10 buckets (as you show in the data) you are ready and you can say nothing about the distribution.
Example of a Uniform Distribution
create table r as
select
1 + trunc((rownum-1)/2) A
from dual connect by level <= 1000;
select count(*), count(distinct a), min(a), max(a) from r;
COUNT(*) COUNT(DISTINCTA) MIN(A) MAX(A)
---------- ---------------- ---------- ----------
1000 500 1 500
Create FREQUENCY Histogram with 500 Buckets
exec dbms_stats.gather_table_stats(ownname=>user, tabname=>'R', method_opt=>'for all columns size 500');
select NUM_BUCKETS, HISTOGRAM from user_tab_columns where table_name = 'R';
NUM_BUCKETS HISTOGRAM
----------- ---------------
500 FREQUENCY
select ENDPOINT_VALUE, ENDPOINT_NUMBER from user_histograms where table_name = 'R' order by ENDPOINT_VALUE;
ENDPOINT_VALUE, ENDPOINT_NUMBER
1 2
2 4
3 6
4 8
...
498 996
499 998
500 1000
I have a pretty lengthy SQL query which I'm going to run on Oracle via hibernate. It consists of two nested selects. In the first select statement, a number of sums are calculated, but in one of them I want to filter the results using unique ids.
SELECT ...
SUM(NVL(CASE WHEN SECOND_STATUS= 50 OR SECOND_STATUS IS NULL THEN RECEIVE_AMOUNT END, 0) +
NVL(CASE WHEN FIRST_STATUS = 1010 THEN AMOUNT END, 0) +
NVL(CASE WHEN FIRST_STATUS = 1030 THEN AMOUNT END, 0) -
NVL(CASE WHEN FIRST_STATUS = 1010 AND (SECOND_STATUS= 50 OR SECOND_STATUS IS NULL) THEN RECEIVE_AMOUNT END, 0)) TOTAL, ...
And at the end:
... FROM (SELECT s.*, p.* FROM FIRST_TABLE s
JOIN SECOND_TABLE p ON s.ID = p.FIRST_ID
In one of the lines that start with NVL (second line actually), I want to add a distinct clause that sums the amounts only if first table ids are unique. But I don't know if this is possible or not. If yes, how would it be?
Assume such setup
select * from first;
ID AMOUNT
---------- ----------
1 10
2 20
select * from second;
SECOND_ID FIRST_ID AMOUNT2
---------- ---------- ----------
1 1 100
2 1 100
3 2 100
After the join you get the total sum of both amounts too high because the amount from the first table is duplicated.
select *
from first
join second on first.id = second.first_id;
ID AMOUNT SECOND_ID FIRST_ID AMOUNT2
---------- ---------- ---------- ---------- ----------
1 10 1 1 100
1 10 2 1 100
2 20 3 2 100
You must add a row_number that identifies the first occurence in the parent table and consider in the AMOUNT only the first row and resets it to NULL in the duplicated rows.
select ID,
case when row_number() over (partition by id order by second_id) = 1 then AMOUNT end as AMOUNT,
SECOND_ID, FIRST_ID, AMOUNT2
from first
join second on first.id = second.first_id;
ID AMOUNT SECOND_ID FIRST_ID AMOUNT2
---------- ---------- ---------- ---------- ----------
1 10 1 1 100
1 2 1 100
2 20 3 2 100
Now you can safely sum in a separate subquery
with tab as (
select ID,
case when row_number() over (partition by id order by second_id) = 1 then AMOUNT end as AMOUNT,
SECOND_ID, FIRST_ID, AMOUNT2
from first
join second on first.id = second.first_id
)
select id, sum(nvl(amount,0) + nvl(amount2,0))
from tab
group by id
;
ID SUM(NVL(AMOUNT,0)+NVL(AMOUNT2,0))
---------- ---------------------------------
1 210
2 120
Note also that this is an answer to your question. Some will argue that in your situation you should first aggregate and than join. This will also resolve your problem possible more elegantly.
i have 2 tables
Table 1
col1 col2
---- ----
BLANK A
D A
V A
BLANK B
D B
V B
Table 2
col1 col2 sex age
---- ---- ---- ----
A as M 45
A sa F 32
A asd F 45
B as M 45
B sa F 32
B asd F 45
my output should be in a order like for each value in col1 of Table 1 should be repeated with the Table2 values and that to in the order and in the second table it should be ordered by Sex and for Female records alone we need to order them by age older first. finally the output table should look like below.
COL1 COL2 COL3 SEX AGE
---- ----- ---- --- ---
BLANK A as M 45
BLANK A asd F 45
BLANK A sa F 32
D A as M 45
D A asd F 45
D A sa F 32
V A as M 45
V A asd F 45
V A sa F 32
BLANK B as M 45
BLANK B asd F 45
BLANK B sa F 32
D B as M 45
D B asd F 45
D B sa F 32
V B as M 45
V B asd F 45
V B sa F 32
If you just want the rows repeating for each value without any join criteria, something like this should do (although I don't have Sybase to test on, it's fairly straight forward SQL);
SELECT t1.col1, t1.col2, t2.col2 AS col3, sex, age
FROM Table1 t1, Table2 t2
ORDER BY t1.col1, sex DESC, age DESC
An SQL Server SQLfiddle as a sample.
EDIT: After your edited question, I assume you want to pair t1.col2 with the corresponding t2.col1, then this ordering should be the correct one;
SELECT t1.col1, t1.col2, t2.col2 AS col3, sex, age
FROM Table1 t1
JOIN Table2 t2
ON t1.col2 = t2.col1
ORDER BY t1.col2, t1.col1, sex DESC, age DESC
Another SQLfiddle.
Consider the following
Sample Input
SalesBoyName Product Amount
------------ ------- ------
Boy1 P1 100
Boy1 P1 40
Boy1 P2 100
Boy2 P1 100
Boy2 P3 12
Desired Output
SalesBoyName P1 P2 P3
------------ ---- ---- ----
Boy1 140 100 null
Boy2 100 null 12
The below SQL SERVER 2005 query will do the work
SELECT SalesBoyName, [P1] AS P1, [P2] AS P2,[P3] AS P3
FROM
(SELECT * FROM tblSales ) s
PIVOT
(
SUM (Amount)
FOR Product IN
( [P1], [P2], [P3])
) AS pvt
I want to perform the same thing in Oracle 10g.
How to do this?
This may be trivial, but since i am very new to Oracle, so I am seeking for help.
Thanks
You can do it like this in 10G:
select salesboyname,
sum (case when product='P1' then amount end) as p1,
sum (case when product='P2' then amount end) as p2,
sum (case when product='P3' then amount end) as p3
from tblsales
group by salesboyname;
In 11G there is a PIVOT keyword similar to SQL Server's.
First off, I'm a total Oracle noob although I'm very familiar with SQL. I have a single cost column. I need to calculate the total cost, the percentage of the total cost, and then a running sum of the percentages. I'm having trouble with the running sum of percentages because the only way I can think to do this uses nested SUM functions, which isn't allowed.
Here's what works:
SELECT cost, SUM(cost) OVER() AS total, cost / SUM(cost) OVER() AS per
FROM my_table
ORDER BY cost DESC
Here's what I'm trying to do that doesn't work:
SELECT cost, SUM(cost) OVER() AS total, cost / SUM(cost) OVER() AS per,
SUM(cost/SUM(cost) OVER()) OVER(cost) AS per_sum
FROM my_table
ORDER BY cost DESC
Am I just going about it wrong, or is what I'm trying to do just not possible? By the way I'm using Oracle 10g. Thanks in advance for any help.
You don't need the order by inside that inline view, especially since the outer select is doing an order by the order way around. Also, cost / SUM(cost) OVER () equals RATIO_TO_REPORT(cost) OVER ().
An example:
SQL> create table my_table(cost)
2 as
3 select 10 from dual union all
4 select 20 from dual union all
5 select 5 from dual union all
6 select 50 from dual union all
7 select 60 from dual union all
8 select 40 from dual union all
9 select 15 from dual
10 /
Table created.
Your initial query:
SQL> SELECT cost, SUM(cost) OVER() AS total, cost / SUM(cost) OVER() AS per
2 FROM my_table
3 ORDER BY cost DESC
4 /
COST TOTAL PER
---------- ---------- ----------
60 200 .3
50 200 .25
40 200 .2
20 200 .1
15 200 .075
10 200 .05
5 200 .025
7 rows selected.
Quassnoi's query contains a typo:
SQL> SELECT cost, total, per, SUM(running) OVER (ORDER BY cost)
2 FROM (
3 SELECT cost, SUM(cost) OVER() AS total, cost / SUM(cost) OVER() AS per
4 FROM my_table
5 ORDER BY
6 cost DESC
7 )
8 /
SELECT cost, total, per, SUM(running) OVER (ORDER BY cost)
*
ERROR at line 1:
ORA-00904: "RUNNING": invalid identifier
And if I correct that typo. It gives the right results, but wrongly sorted (I guess):
SQL> SELECT cost, total, per, SUM(per) OVER (ORDER BY cost)
2 FROM (
3 SELECT cost, SUM(cost) OVER() AS total, cost / SUM(cost) OVER() AS per
4 FROM my_table
5 ORDER BY
6 cost DESC
7 )
8 /
COST TOTAL PER SUM(PER)OVER(ORDERBYCOST)
---------- ---------- ---------- -------------------------
5 200 .025 .025
10 200 .05 .075
15 200 .075 .15
20 200 .1 .25
40 200 .2 .45
50 200 .25 .7
60 200 .3 1
7 rows selected.
I think this is the one you are looking for:
SQL> select cost
2 , total
3 , per
4 , sum(per) over (order by cost desc)
5 from ( select cost
6 , sum(cost) over () total
7 , ratio_to_report(cost) over () per
8 from my_table
9 )
10 order by cost desc
11 /
COST TOTAL PER SUM(PER)OVER(ORDERBYCOSTDESC)
---------- ---------- ---------- -----------------------------
60 200 .3 .3
50 200 .25 .55
40 200 .2 .75
20 200 .1 .85
15 200 .075 .925
10 200 .05 .975
5 200 .025 1
7 rows selected.
Regards,
Rob.
SELECT cost, total, per, SUM(per) OVER (ORDER BY cost)
FROM (
SELECT cost, SUM(cost) OVER() AS total, cost / SUM(cost) OVER() AS per
FROM my_table
)
ORDER BY
cost DESC