Conversion from standard SQL to Oracle Syntax - oracle

I have a problem with converting a standard SQL join into the old Oracle join syntax (please don't ask me why I need that). I would expect the same result, anyway, it is not:
Sample Data:
create table testing (
aid number(8),
bid number(8),
btext varchar(80));
insert into testing values (100,1,'text1a');
insert into testing values (100,2,'text1b');
insert into testing values (100,3,'text1c');
insert into testing values (200,19,'text2b');
insert into testing values (200,18,'text2a');
insert into testing values (300,4324,'text3a');
insert into testing values (500,80,'text4a');
insert into testing values (50,2000,'text5a');
commit;
Standard SQL:
select a.*,b.* from testing a
left outer join testing b
on (a.aid = b.aid and a.bid < b.bid)
order by a.aid, b.bid;
AID BID BTEXT AID_1 BID_1 BTEXT_1
50 200 text5a NULL NULL NULL
100 1 text1a 100 2 text1b
100 2 text1b 100 3 text1c
100 1 text1a 100 3 text1c
100 3 text1c NULL NULL NULL
200 18 text2a 200 19 text2b
200 19 text2b NULL NULL NULL
300 432 text3a NULL NULL NULL
500 80 text4a NULL NULL NULL
Oracle SQL:
select a.*,b.* from testing a, testing b
where a.aid = b.aid(+)
and a.bid < b.bid
order by a.aid, b.bid;
AID BID BTEXT AID_1 BID_1 BTEXT_1
100 1 text1a 100 2 text1b
100 2 text1b 100 3 text1c
100 1 text1a 100 3 text1c
200 18 text2a 200 19 text2b
How to get the same result of the standart SQL using Oracle's legacy syntax?

Your Oracle-style statement needs the (+) operator also on the less-than condition, since that is also part of your join criteria in the standard-SQL version.
select a.*,b.* from testing a, testing b
where a.aid = b.aid(+)
and a.bid < b.bid(+)
order by a.aid, b.bid;
See sqlfiddle here.

Related

Inactivate duplicate record and re-point child records to active one

There are two table as below
Table1
ID Name Age Active PID
-----------------------------
1 A 2 Y 100
2 A 2 Y 100
3 A 2 Y 100
4 B 3 Y 200
5 B 3 Y 200
Table2
T2ID CID
---------
10 1
20 1
30 1
40 2
50 2
60 3
70 3
80 3
90 4
100 5
110 5
I am trying to inactivate the duplicate record of table 1 and reassign the table2 record to activated rows of table 1,The result for table1 and table2 should be as below
ID Name Age Active PID
-----------------------------
1 A 2 Y 100
2 A 2 N 100
3 A 2 N 100
4 B 3 N 200
5 B 3 Y 200
T2ID CID
---------
10 1
20 1
30 1
40 1
50 1
60 1
70 1
80 1
90 5
100 5
110 5
please help for oracle query to update
You can do this by using two merge statements, like so:
Update table2:
MERGE INTO table2 tgt
USING (WITH t1 AS (SELECT ID,
NAME,
age,
active,
pid,
MIN(ID) OVER (PARTITION BY pid) min_id,
CASE WHEN COUNT(CASE WHEN active = 'Y' THEN 1 END) OVER (PARTITION BY pid) > 1 THEN 'Y' ELSE 'N' END multi_active_rows
FROM table1)
SELECT t2.t2id,
t2.cid old_cid,
t1.min_id new_cid
FROM t1
INNER JOIN table2 t2 ON t1.id = t2.cid
WHERE t1.multi_active_rows = 'Y') src
ON (tgt.t2id = src.t2id)
WHEN MATCHED THEN
UPDATE SET tgt.cid = src.new_cid;
Update table1:
MERGE INTO table1 tgt
USING (WITH t1 AS (SELECT ID,
NAME,
age,
active,
pid,
MIN(ID) OVER (PARTITION BY pid) min_id,
CASE WHEN COUNT(CASE WHEN active = 'Y' THEN 1 END) OVER (PARTITION BY pid) > 1 THEN 'Y' ELSE 'N' END multi_active_rows
FROM table1)
SELECT ID
FROM t1
WHERE multi_active_rows = 'Y'
AND ID != min_id) src
ON (tgt.id = src.id)
WHEN MATCHED THEN
UPDATE SET active = 'N';
Since we want to derive the results to update both table1 and table2 from the original dataset in table1, it's easier to update table2 first before updating table1.
This works by finding the lowest id across each set of pids in table1, plus checking to see if there is more than one active row for each pid (there's no need to do any updates if we have at most one active row available).
Once we have that information, we can use that to decide which rows to update in each table, and we can use the min_id to update table2 with, and we can update any rows in table1 where the id doesn't match the min_id to be not active.
N.B. If you could have a mix of Ys and Ns in your data, you may need to skip the and id != min_id check in the second merge statement and amend the update part to update the row to Y if the id is the min_id, otherwise set it to N.

how to get following output in oracle using query?

I've following data like
ano asal
------------------
1 100
1 150
1 190
2 200
2 240
3 300
3 350
4 400
4 400
4 400
i want ans like max sal from 1 ,from 2,3 and 4
o/p like
ano asal
---------------
1 190
2 240
3 390
4 400
4 400
4 400
You want to return the max value of asal for each ano group, but you want to retain the duplicates in the original table if they exist. This means you can't just do a simple GROUP BY. But you can use a GROUP BY query to identify the max values and then retain those records via an INNER JOIN. Try this query:
SELECT t1.ano, t1.asal
FROM yourTable t1
INNER JOIN
(
SELECT ano, MAX(asal) AS asal
FROM yourTable
GROUP BY ano
) t2
ON t1.ano = t2.ano AND t1.asal = t2.asal
You can use an union the firt select with group by
select ano, max(asal)
from my_table
where ano != 4
group by ano
union all
select ano, asal
from my_table
where ano = 4
order by ano
SELECT
ano, asal
FROM (
SELECT
data.*,
MAX(asal) OVER (PARTITION BY ano) max
FROM
data)
WHERE
asal = max

PIVOT table in Oracle

Can you help me to pivot the details in my Oracle table PAY_DETAILS
PAY_NO NOT NULL NUMBER
EMP_NO NOT NULL VARCHAR2(10)
EMP_ERN_DDCT_NO NOT NULL VARCHAR2(21)
ERN_DDCT_CATNO NOT NULL VARCHAR2(10)
ERN_DDCT_CATNAME NOT NULL VARCHAR2(1000)
PAY_MONTH NOT NULL DATE
AMOUNT NOT NULL NUMBER(10,2)
EARN_DEDUCT NOT NULL VARCHAR2(2)
select EMP_NO,EMP_ERN_DDCT_NO,AMOUNT,EARN_DEDUCT, ERN_DDCT_CATNO from pay_details
EMP_NO EMP_ERN_DDCT_NO AMOUNT EA ERN_DDCT_C
---------- --------------------- ---------- -- ----------
219 10 175 A 001
219 1 5000 A 002
794 7 50000 A 001
769 6 35000 A 001
465 4 5000 A 002
289 2 5000 A 002
435 3 5000 A 002
816 38 5 D 201
737 30 5 D 201
Is it possible to make this output into a cross tab?
So, lets assume you want to pivot your salary data for each month. You can use the following query.
SELECT * FROM
(
SELECT emp_no,
emp_ern_ddct_no,
pay_month,
amount
FROM pay_details
)
PIVOT
(
SUM(amount)
FOR pay_month IN ('01/01/2016', '02/01/2016', '03/01/2016','04/01/2016','05/01/2016','06/01/2016','07/01/2016','08/01/2016','09/01/2016','10/01/2016','11/01/2016','12/01/2016')
)
ORDER BY emp_no;
This is just an example, you can PIVOT your data based on different columns. For more details refer to the following link.
http://www.techonthenet.com/oracle/pivot.php
http://www.oracle-developer.net/display.php?id=506
Since you are on Oracle 10g PIVOT wont work. Try using something similar to the below query.
SELECT emp_no,
SUM(CASE WHEN pay_month ='01/01/2016' THEN AMOUNT ELSE 0 END) jan_pay,
SUM(CASE WHEN pay_month ='02/01/2016' THEN AMOUNT ELSE 0 END) feb_pay,
SUM(CASE WHEN pay_month ='03/01/2016' THEN AMOUNT ELSE 0 END) march_pay
.........
FROM pay_details
GROUP BY emp_no;

sql query to get the column data in one row

I have below data in a table called data_tab
sn code
2 101
2
2 202
5 103
5
5
How can i query to see result in one row, like
sn code1 code2 code3
2 101 202
5 103
Hi This gives the intented output ... take a look here
select sn,
max(decode(rn,1,code)) as CODE_1
,max(decode(rn,2,code)) as CODE_2
,max(decode(rn,3,code)) as CODE_3
from
(
select sn,
code,
row_number() over (partition by sn order by null ) rn
from test
)
group by sn

Is there a more efficient way to count the number of aggregate records in Oracle SQL?

I have more experience with MySQL and MSSQL but I don't consider myself a SQL expert.
I have a requirement for some SQL work running on an Oracle database. Not even sure the version yet but it should be somewhat recent (10, 11??).
Anyway, I have to count the number of distinct records that spans two tables. For sake of argument, let's call them master and detail.
The following SQL gives me the number I want against the data. However, this SQL will eventually be put in a UDF (or Oracle equivalent). But my question is, is there a better way? Either using some advanced Oracle optimization or even just a better SQL query.
Thanks
select count(*) from
(
select
mas.barcode
, det.barcode_val
from mas
inner join det on (det.trans_id = mas.trans_id and mas.trans_sub_id = det.trans_sub_id)
where
mas.trans_id = 12345
and det.code_type = 'COMMODORE'
group by
mas.barcode
, det.barcode_val
);
Data:
MAS
trans_id trans_sub_id barcode
-------------------------------------
12345 1 COM_A
12345 2 COM_A
12345 3 COM_B
DET
trans_id trans_sub_id code_type barcode_val
-------------------------------------------------------
12345 1 COMMODORE C64
12345 1 COMMODORE C64
12345 1 TANDY TRASH80
12345 2 COMMODORE C128
12345 2 ATARI 800XL
12345 2 COMMODORE AMIGA500
12345 3 COMMODORE C64
Results before count
--------------------
COM_A C64
COM_A C128
COM_A AMIGA500
COM_B C64
Results after count
-------------------
4
SELECT
COUNT(DISTINCT mas.barcode || det.barcode_val)
FROM mas
INNER JOIN det
ON (det.trans_id = mas.trans_id and mas.trans_sub_id = det.trans_sub_id)
WHERE
mas.trans_id = 12345
AND det.code_type = 'COMMODORE'
or
SELECT COUNT(*) FROM (
SELECT DISTINCT mas.barcode, det.barcode_val
FROM mas
INNER JOIN det
ON (det.trans_id = mas.trans_id and mas.trans_sub_id = det.trans_sub_id)
WHERE
mas.trans_id = 12345
AND det.code_type = 'COMMODORE'
)
If you use the
COUNT(DISTINCT mas.barcode || det.barcode_val)
make sure to put a delimiter between the pipeline:
COUNT(DISTINCT mas.barcode || '-' || det.barcode_val)
For example imagine the following scenario:
Column1 Column2 Column1 || Column2 Column1 || '-' || Column2
A B AB A-B
AB <null> AB AB-
1 201 1201 1-201
<null> 1201 1201 -1201
This table has 4 rows with 4 different values. But if you try a
COUNT(DISTINCT COLUMN1 || COLUMN2)
you would get just 2 "distinct" groups.
Just a tip to try to avoid those corner cases.

Resources