Oracle: Taking columns from rows and putting them side by side - oracle

I'm having trouble figuring out how to do something in Oracle. I have this table:
| id | rownum | code | gift |
|-----|--------|-----------|------|
|2000 | 1 | Ganymede | 437 |
|2000 | 2 | Alpha | 50 |
|2000 | 3 | Ambergris | 600 |
And the client wants it to look like this:
| id | code_1 | gift_1 | code_2 | gift_2 | code_3 | gift_3 |
|----|--------|--------|--------|--------|-----------|--------|
|2000|Ganymede| 437 | Alpha | 50 | Ambergris | 600 |
I'm not quite sure how to go about doing this using PIVOT.

You can use PIVOT:
SELECT id,
"1_CODE" AS code_1,
"1_GIFT" AS gift_1,
"2_CODE" AS code_2,
"2_GIFT" AS gift_2,
"3_CODE" AS code_3,
"3_GIFT" AS gift_3
FROM table_name
PIVOT (
MAX(code) AS code,
MAX(gift) AS gift
FOR "ROWNUM" IN (1, 2, 3)
)
or conditional aggregation:
SELECT id,
MAX(CASE "ROWNUM" WHEN 1 THEN code END) AS code_1,
MAX(CASE "ROWNUM" WHEN 1 THEN gift END) AS gift_1,
MAX(CASE "ROWNUM" WHEN 2 THEN code END) AS code_2,
MAX(CASE "ROWNUM" WHEN 2 THEN gift END) AS gift_2,
MAX(CASE "ROWNUM" WHEN 3 THEN code END) AS code_3,
MAX(CASE "ROWNUM" WHEN 3 THEN gift END) AS gift_3
FROM table_name
GROUP BY id
Which, for the sample data:
CREATE TABLE table_name (id, "ROWNUM", code, gift ) AS
SELECT 2000, 1, 'Ganymede', 437 FROM DUAL UNION ALL
SELECT 2000, 2, 'Alpha', 50 FROM DUAL UNION ALL
SELECT 2000, 3, 'Ambergris', 600 FROM DUAL;
Both output:
ID
CODE_1
GIFT_1
CODE_2
GIFT_2
CODE_3
GIFT_3
2000
Ganymede
437
Alpha
50
Ambergris
600
db<>fiddle here

Related

Count Max number of day continious overdraff

Date | Account | Amount | Count max number of day continuous < 0 |
1 | 1001 | 100 | 0 |
2 | 1001 | -100 | 1 |
3 | 1001 | -100 | 2 |
4 | 1001 | 100 | 2 |
5 | 1001 | -100 | 2 |
6 | 1001 | -100 | 2 |
7 | 1001 | -100 | 3 |
8 | 1001 | -100 | 4 |
9 | 1001 | 100 | 4 |
I have sample data. I want have column "Count max number of day continuous < 0". How i can select it in database oracle
In order to find continuous periods you can use Tabibitosian method. Then use analytical count and finally max:
select date_, account, amount,
max(cnt) over (partition by account order by date_) max_overdraft_period
from (
select date_, account, amount,
count(case when amount <= 0 then 1 end)
over (partition by account, grp order by date_) cnt
from (
select date_, account, amount,
date_ - sum(case when amount <= 0 then 1 else 0 end)
over (partition by account order by date_) grp
from t ))
demo
I assumed that dates are continuous, if not then use row numbering at first.

Use count(decode...) across multiple tables

I have three 3 tables (having the same key) in the following structure:
Input Table t1:
file_in| f_in_state|
--------------------
F01 | 1 |
F02 | 2 |
F21 | 1 |
F41 | 2 |
Input Table t2:
line_in| file_in| l_in_state |
-----------------------------
L001 | F01 | 1 |
L002 | F01 | 2 |
L003 | F01 | 2 |
L004 | F01 | 2 |
L005 | F21 | 1 |
L006 | F21 | 1 |
L007 | F21 | 1 |
L008 | F21 | 1 |
Input Table t3:
line_out|line_in| file_in| l_out_state|
---------------------------------------
D001 |L001 | F01 | 1 |
D002 |L002 | F01 | 1 |
D003 |L003 | F01 | 1 |
and I need to count the number of occurrences of the columns refering to the different states across my three tables for each "file in id" and then combine them to get an output like this:
file_in_id|file_in_state| A | B | C | D | E |
---------------------------------------------
F01 | 1 | 1 | 3 | 0 | 0 | 3 |
F02 | 2 | 2 | 0 | 0 | 0 | 0 |
F21 | 1 | 1 | 4 | 0 | 0 | 0 |
F41 | 2 | 2 | 0 | 0 | 0 | 0 |
with:
A refers to the number of input lines ("line_in") having the state = '1'
B refers to the number of input lines ("line_in") having the state = '2'
C refers to the number of input lines ("line_in") having the state = '3' (in my case, there is no line with this state, but it is possible to happen)
D refers to the number of output lines ("line_out") having the state = '1'
E refers to the number of output lines ("line_out") having the state = '2'
So, I tried to use the decode function in my query but I didn't get the wished result.
SELECT
t1.file_in AS file_in_id,
t1.f_in_state AS file_in_state,
COUNT(DECODE(t2.f_in_state, '1', 1, null)) AS A,
COUNT(DECODE(t2.f_in_state, '2', 1, null)) AS B,
COUNT(DECODE(t2.f_in_state, '3', 1, null)) AS C,
COUNT(DECODE(t3.f_out_state, '1', 1, null)) AS D,
COUNT(DECODE(t3.f_out_state, '2', 1, null)) AS E
FROM table1 t1,
table2 t2,
table3 t3
WHERE t1.file_in = t2.file_in (+)
AND t2.file_in = t3.file_in (+)
GROUP BY t1.file_in, t1.f_in_state
ORDER BY t1.file_in
But, this is what I get :
file_in_id|file_in_state|A |B |C |D |E |
----------------------------------------
F01 |1 |1 |3 |9 |0 |12|
F02 |2 |2 |0 |0 |0 |0 |
F21 |1 |1 |4 |0 |0 |0 |
F41 |2 |2 |0 |0 |0 |0 |
Could somebody tells me what is wrong with this query and how can I fix it to get what I would like to have as a result.
It's very important, this is how the input table 3 should be :
Input Table t3:
line_out|*file_out*| file_in| l_out_state|
---------------------------------------
D001 |W01 | F01 | 1 |
D002 |W01 | F01 | 1 |
D003 |W01 | F01 | 1 |
This query gives desired result:
select file_in, f_in_state,
count(case l_in_state when '1' then 1 end) a,
count(case l_in_state when '2' then 1 end) b,
count(case l_in_state when '3' then 1 end) c,
count(case l_out_state when '1' then 1 end) d,
count(case l_out_state when '2' then 1 end) e
from t1
left join t2 using (file_in)
left join t3 using (file_in, line_in)
group by file_in, f_in_state
order by file_in
You could also use pivot if you have Oracle 11g or above.
Test:
with t1(file_in, f_in_state) as (
select 'F01', '1' from dual union all
select 'F02', '2' from dual union all
select 'F21', '1' from dual union all
select 'F41', '2' from dual ),
t2(line_in, file_in, l_in_state) as (
select 'L001', 'F01', '1' from dual union all
select 'L002', 'F01', '2' from dual union all
select 'L003', 'F01', '2' from dual union all
select 'L004', 'F01', '2' from dual union all
select 'L005', 'F21', '1' from dual union all
select 'L006', 'F21', '1' from dual union all
select 'L007', 'F21', '1' from dual union all
select 'L008', 'F21', '1' from dual ),
t3(line_out, line_in, file_in, l_out_state) as (
select 'D001', 'L001', 'F01', '1' from dual union all
select 'D002', 'L002', 'F01', '1' from dual union all
select 'D003', 'L003', 'F01', '1' from dual )
select file_in, f_in_state,
count(case l_in_state when '1' then 1 end) a,
count(case l_in_state when '2' then 1 end) b,
count(case l_in_state when '3' then 1 end) c,
count(case l_out_state when '1' then 1 end) d,
count(case l_out_state when '2' then 1 end) e
from t1
left join t2 using (file_in)
left join t3 using (file_in, line_in)
group by file_in, f_in_state
order by file_in
Output:
FILE_IN F_IN_STATE A B C D E
------- ---------- ---------- ---------- ---------- ---------- ----------
F01 1 1 3 0 3 0
F02 2 0 0 0 0 0
F21 1 4 0 0 0 0
F41 2 0 0 0 0 0
Variant with SUM
Select a.file_in, a.f_in_state,
Sum(Case When b.l_in_state=1 Then 1 Else 0 End) A,
Sum(Case When b.l_in_state=2 Then 1 Else 0 End) B,
Sum(Case When b.l_in_state=3 Then 1 Else 0 End) C,
Sum(Case When c.l_out_state=1 Then 1 Else 0 End) D,
Sum(Case When c.l_out_state=2 Then 1 Else 0 End) E
From T1 a
Left join T2 b on a.file_in=b.file_in
Left join T3 c on a.file_in=c.file_in and b.line_in=c.line_in
GROUP BY a.file_in, a.f_in_state
ORDER BY a.file_in

Return a value if null

In oracle, I have a piece of code that returns our work order pass rate. It essentially takes the number of failures (MRB) and divides by the number of work orders processed (WO) to give the rate. The problem I have is that unless there is a failure (MRB) I will not get a return for the corresponding month. If there is no MRB failure, I would like a return of 100% for that month. Here is the code I am working with. For the record, I am not a programmer, I've just picked up a bit of info along the way. I have tried adding NVL but that does not seem to help.
Select To_Char(MTH, 'Month') As "Month",WO, MRB,
Round(1 - (MRB / WO), 3) * 100 As "Pass Rate",
'98' As Goal
From
(
Select Trunc(g.START_DATE, 'Month') As mth,
Count(Distinct V_PDAYPROD_CRW1.PDAYPROD_ID) As WO,
Count(Distinct V_WF_HEADER_MRB.ID) As MRB
From GLPERIODS g
Left Join V_PDAYPROD_CRW1 On Trunc(g.START_DATE, 'Month') = Trunc(V_PDAYPROD_CRW1.PROD_DATE, 'Month')
Left Join V_WF_HEADER_MRB On Trunc(g.START_DATE, 'Month') = Trunc(V_WF_HEADER_MRB.OPEN_DATE, 'Month')
Inner Join ARINVT On V_PDAYPROD_CRW1.ARINVT_ID = ARINVT.ID
Where Extract(Year From g.START_DATE) = Extract(Year From SysDate)
And V_WF_HEADER_MRB.WF_TYPE_ID = '99'
And V_WF_HEADER_MRB.EPLANT_ID = 2
And ARINVT.EPLANT_ID = 2
Group By Trunc(g.START_DATE, 'Month'),
V_WF_HEADER_MRB.WF_TYPE_ID
)
Group By To_Char(MTH, 'Month'),WO,MRB,
Round(1 - (MRB / WO), 3) * 100,
'98',MTH
Order By MTH
The above code returns the following:
MONTH | WO | MRB | Pass Rate | GOAL
September | 60 | 1 | 98.3 | 98
December | 30 | 2 | 93.3 | 98
I would like it to return something like this:
MONTH | WO | MRB | Pass Rate | GOAL
January | 25 | 0 | 100 | 98
February | 66 | 0 | 100 | 98
March | 35 | 0 | 100 | 98
April | 22 | 0 | 100 | 98
May | 19 | 0 | 100 | 98
June | 47 | 0 | 100 | 98
July | 52 | 0 | 100 | 98
August | 55 | 0 | 100 | 98
September | 60 | 1 | 98.3 | 98
October | 39 | 0 | 100 | 98
November | 18 | 0 | 100 | 98
December | 30 | 2 | 93.3 | 98
Thank you for any help you can offer.
If you expect all the records from the main table to be returned in the result set then you should not use the filtering criteria on "v_wf_header_mrb" table in the where clause.
Remove "V_WF_HEADER_MRB.WF_TYPE_ID = '99' And V_WF_HEADER_MRB.EPLANT_ID = 2 " condition from Where clause and try.
You can use the below query instead.
SELECT
TO_CHAR(mth,'Month') AS "Month",
wo,
mrb,
round(1 - (mrb / wo),3) * 100 AS "Pass Rate",
'98' AS goal
FROM
(
SELECT
trunc(g.start_date,'Month') AS mth,
COUNT(DISTINCT v_pdayprod_crw1.pdayprod_id) AS wo,
COUNT(DISTINCT v_wf_header_mrb.id) AS mrb
FROM
glperiods g
LEFT JOIN
v_pdayprod_crw1
ON
trunc(g.start_date,'Month') = trunc(v_pdayprod_crw1.prod_date,'Month')
LEFT JOIN
v_wf_header_mrb
ON
trunc(g.start_date,'Month') = trunc(v_wf_header_mrb.open_date,'Month')
AND
v_wf_header_mrb.wf_type_id = '99'
AND
v_wf_header_mrb.eplant_id = 2
INNER JOIN
arinvt
ON
v_pdayprod_crw1.arinvt_id = arinvt.id
WHERE
EXTRACT(YEAR FROM g.start_date) = EXTRACT(YEAR FROM SYSDATE)
AND
arinvt.eplant_id = 2
GROUP BY
trunc(g.start_date,'Month'),
v_wf_header_mrb.wf_type_id
)
GROUP BY
TO_CHAR(mth,'Month'),
wo,
mrb,
round(1 - (mrb / wo),3) * 100,
'98',
mth
ORDER BY mth;

Edit Total line in Oracle report 1

The data structure:
sql-> desc t1
- List item
p_code number,
acc_date date ,
debit number,
credit number
Data inside my table:
sql-> select * from t1;
| p_code | acc_date | debit | credit |
| 001 | 01-01-15 | 100 | 25 |
| 001 | 02-01-15 | 0 | 125 |
| 001 | 03-01-15 | 415 | 85 |
I would like to do something like this:
select * from t1
where acc_date between :fromdate and :todate
union all
select p_code, (sum(nvl(debit,0))- sum(nvl(credit,0))) open_balance
from t1
where acc_date < :fromdate
;
But, I can't figure out what are my mistakes.
Type and number of columns in union must be the same -
select p_code, acc_date, debit, credit, null as open_balance
from t1
where acc_date between :fromdate and :todate
union all
select p_code, null as acc_date, null as debit, null as credit,
(sum(nvl(debit, 0)) - sum(nvl(credit, 0))) open_balance
from t1
where acc_date < :fromdate

SQL bring back highest sum of rows

I'm looking to calculate the highest basket in my set of data but I can't get my head around how I should do it.
I have data like:
OrderID | CustomerID | BasketID | ProductID | Price
1 | 1 | 1 | 221 | 10
2 | 1 | 1 | 431 | 123
3 | 1 | 2 | 761 | 44
4 | 2 | 3 | 12 | 54
5 | 2 | 3 | 102 | 78
6 | 3 | 4 | 111 | 98
7 | 3 | 4 | 41 | 45
8 | 3 | 5 | 65 | 66
9 | 4 | 6 | 32 | 47
10 | 4 | 6 | 118 | 544
Sorry if it seems quite messy.
But I can easily get the SUM with an obvious
SELECT SUM([Price]), BasketID, CustomerID FROM table
GROUP BY BasketID, CustomerID
But how can I filter the list for only the highest priced Basket ID for that CustomerID
Thanks
You can use a CTE (Common Table Expression) with the ROW_NUMBER function:
;WITH HighestPricePerCustomerAndBasket AS
(
SELECT
ID, UserID, ClassID, SchoolID, Created,
ROW_NUMBER() OVER(PARTITION BY BasketID,CustomerID ORDER BY Price DESC) AS 'RowNum'
FROM dbo.YourTable
)
SELECT
[Price], BasketID, CustomerID
FROM HighestPricePerCustomerAndBasket
WHERE RowNum = 1
This CTE "partitions" your data by BasketID,CustomerID, and for each partition, the ROW_NUMBER function hands out sequential numbers, starting at 1 and ordered by Price DESC - so the first row (highest price) gets RowNum = 1 (for each BasketID,CustomerID "partition") which is what I select from the CTE in the SELECT statement after it.
SELECT *
FROM (SELECT *,
DENSE_RANK() OVER (PARTITION BY CustomerID ORDER BY BasketTotal DESC) AS RNK
FROM (SELECT Sum(Price) AS BasketTotal,
BasketID,
CustomerID
FROM Order a
GROUP BY BasketID,
CustomerID
) a
) b
WHERE RNK = 1
I managed to conjure something up that worked.

Resources