Sql Query Problem - oracle

i have problem when joining tables(left join)
table1:
id1 amt1
1 100
2 200
3 300
table2:
id2 amt2
1 150
2 250
2 350
my Query:
select id1,amt1,id2,amt2 from table1
left join table2 on table2.id1=table1.id2
my supposed o/p is:
id1 amt1 id2 amt2
row1: 1 100 1 150
row2: 2 200 2 250
row3: 2 200 2 350
i want o/p in row3 as
2 null 2 350
ie i want avoid repetetion of data(amt1)
friends help!

Using LEAD and LAG gives acces to previous or following rows in oracle.
SELECT id1, decode(amt1, lag(amt1) over (order by id1, id2), '', amt1) amt1,
id2, amt2
FROM table1 left join table2 on table2.id1=table1.id2
ORDER BY id1, id2
The order of the query and the order given to the lag function should be the same.
Explanation:
If the current am1 is the same as the preceding amt1 (preceding in the given order) then omit the value.
EDIT
According to your comment, add an additional check for id changes.
SELECT id1,
decode(id1, lag(id1) over (order by id1, id2),
decode(amt1, lag(amt1) over (order by id1, id2), '', amt1),
amt1) amt1,
id2, amt2
FROM table1 left join table2 on table2.id1=table1.id2
ORDER BY id1, id2
Use the same LAG feature to check for id changes. The expression is a bit more complex, but its comparable with a nested if statement.

select distinct id1,amt1,id2,amt2 from table1 left join table2 on table2.id1=table1.id2
try this ?

Related

display multiple column records in one column in oracle

I have Table having following columns in Oracle;
ID NIC NTN MBL NAME
---------------------------------------
1 1234512 ABC
2 321 XYZ
3 5421 POI
4 541245 624
I need to display like this in select query
ID NIC/NTN/MBL NAME
1 1234512 ABC
2 321 XYZ
3 5421 POI
4 541245 // taking first value
I was trying to do with
SELECT
A.ID,
"CNIC/NTN/MBL"
A.NAME,
A.REASON
B.NAME
FROM TABLEA A
INNER JOIN TABLEB B ON A.R_ID = B.R_ID
UNPIVOT INCLUDE NULLS
(
CNIC/NTN/MBL FOR cols IN (A.NIC, A.NTN, A.MBL)
)
but unable to do.
Use COALESCE:
SELECT
ID,
COALESCE(NIC, NTN, MBL) AS "NIC/NTN/MBL",
NAME
FROM yourTable;
This should work because in the call to COALESCE above, I list the three columns from left to right, and the first non NULL value will be retained.
You need the COALESCE function (which simply returns the first non-null value in the specified inputs, reading from left to right), like so:
WITH your_table AS (SELECT 1 ID, 1234512 nic, NULL ntn, NULL mbl, 'ABC' NAME FROM dual UNION ALL
SELECT 2 ID, NULL nic, 321 ntn, NULL mbl, 'ABC' NAME FROM dual UNION ALL
SELECT 3 ID, NULL nic, NULL ntn, 5421 mbl, 'ABC' NAME FROM dual UNION ALL
SELECT 4 ID, 541245 nic, 624 ntn, NULL mbl, 'ABC' NAME FROM dual)
SELECT ID,
COALESCE(nic, ntn, mbl) nic_ntn_mbl,
NAME
FROM your_table;
ID NIC_NTN_MBL NAME
---------- ----------- ----
1 1234512 ABC
2 321 ABC
3 5421 ABC
4 541245 ABC

return null if no rows found oracle query with IN clause

I have a table with three columns.
I query that table with IN clause.
select column1 from table1 where column1 in (1,2,3) order by column2, column3
The table1 contains only values 1 and 2 in column1. I want to return the not available value also in my result, and that should be sorted in the bottom.
example data
column1 column 2 column 3
1 100 11
2 101 50
output, the not available values should be in the last.
column1 column 2 column 3
1 100 11
2 101 50
3 null null
I tried with subquery with NVL, like select nvl((select.. in(1,2,3)),null) from dual, due to IN Clause, I am getting single row subquery returns more than one row issue, which is expected.
Also tried with the union but nothing works. Great if any help. Thanks
I think you can do it with a union all:
select column1 from table1 where column1 in (1,2,3) order by column2, column3
union all
select null from table1 where column1 not in (1,2,3) order by column2, column3
If you can't take 1,2,3 values from another table you can try with:
with t1 as (
select col1,col2,col3
from tab1
where cod_flusso in ('1','2','3')),
t2 as (
select '1' as col1,null,null
from dual
union
select '2',null,null
from dual
union
select '3',null,null
from dual)
select t2.col1,col2,col3
from t2
left outer join t1
on t1.col1= t2.col1
It's better if you can store 1,2,3 values in a second table, then use left outer join.

Find completely non-distinct rows

I have an Oracle table I've compiled using an Informatica workflow. It's failing an integrity check because the following queries return a different number of rows:
SELECT DISTINCT * FROM table // 4,000 rows
SELECT * FROM table // 4,006 rows
The table consists of 17 fields, none of which are unique keys (obviously). How can I find the 6 duplicate rows?
For returning duplicate rows.
select * from
(SELECT cd.*,
ROW_NUMBER ()
OVER (PARTITION BY column1,column2...column2
ORDER BY column_names)
seq_no
FROM table cd)
where seq_no>1;
For example i have create one sample_table below for your better understanding.
create table sample_table
(
id1 number,
id2 number
)
i have inserted below data into table
ID1 ID2
1 2
1 2
1 2
2 3
2 3
2 3
In above data set we have 6 rows but only two rows are distinct.
By using below queries we can get distinct rows and non-distinct rows.
SELECT cd.*,
ROW_NUMBER ()
OVER (PARTITION BY id1
ORDER BY id1)
seq_no
FROM sample_table cd
after partition the table with the help of id1 we will get the below results
ID1 ID2 SEQ_NO
1 2 1
1 2 2
1 2 3
2 3 1
2 3 2
2 3 3
Then if you want to see the distinct rows use below query
select * from
(SELECT cd.*,
ROW_NUMBER ()
OVER (PARTITION BY id1
ORDER BY id1)
seq_no
FROM sample_table cd)
where seq_no=1;
if you want to see duplicate set use below query
select * from
(SELECT cd.*,
ROW_NUMBER ()
OVER (PARTITION BY id1
ORDER BY id1)
seq_no
FROM sample_table cd)
where seq_no>1;
A posibiliy is to use a analytical function to count the rows in the same group and I don't see how you can write the query without writing all the columns in some clause:
select *
from (
Select a.*, count(*) over (partition by column1, column2, ..., column17) as cnt
from your_table a
)
where cnt>1
This should get 12 rows, because 6 are duplicated.
A basic sql query would be:
select col1, col2, ..., col17
from table
group by col1, col2, ..., col17
having count(*) > 1;

Group by two fields, and having count() on first field

I have a table that stored users play list, a video can be viewed by multiple users for multiple times.
A records goes like this:
videoid, userid, time
123, abc , 2013-09-11
It means user(abc) has watched video(123) on 2013-09-11
Now I want to find distinct users watched video list (no duplication), and only show the users that have watched more than two videos.
SELECT videoid, userid
FROM table_play_list
WHERE SOME CONDICTION
GROUP BY userid, videoid
The sql only select distinct users watchlist, I also want to filter users that have watched more than two different videos.
I know I have to google and read the documentation first, some said 'HAVING' could solve this, unfortunately, I could not make it.
If I understand correctly, you are looking for users who watched more than two different videos. You can do this by using count(distinct) with a partition by clause:
select userid, videoid
from (SELECT userid, videoid, count(distinct videoid) over (partition by userid) as cnt
FROM table_play_list
WHERE <ANY CONDITION>
) t
where cnt > 2;
Try like this,
SELECT userid, count(*)
FROM table_play_list
--WHERE SOME CONDITION
GROUP BY user_id
having count(*) >2;
Try this if you need to get the count based on userid and videoid(users who watch the same video more than two times).
SELECT userid, videoid, count(*)
FROM table_play_list
--WHERE SOME CONDITION
GROUP BY user_id, video_id
having count(*) >2;
This is probably best handled with analytics (window functions). Without analytics you will probably need a self-join.
SQL> WITH table_play_list AS (
2 SELECT 123 videoid, 'a' userid FROM dual UNION ALL
3 SELECT 125 videoid, 'a' userid FROM dual UNION ALL
4 SELECT 123 videoid, 'b' userid FROM dual UNION ALL
5 SELECT 123 videoid, 'b' userid FROM dual UNION ALL
6 SELECT 123 videoid, 'c' userid FROM dual
7 )
8 SELECT videoid, userid,
9 COUNT(*) over(PARTITION BY userid) nb_video
10 FROM table_play_list;
VIDEOID USERID NB_VIDEO
---------- ------ ----------
123 a 2
125 a 2
123 b 2
123 b 2
123 c 1
This lists all user/video and the total number of videos watched by each user. As you can see user b has watched the same video twice, I don't know if it's possible in your system.
You can filter with a subquery:
SQL> WITH table_play_list AS (
2 SELECT 123 videoid, 'a' userid FROM dual UNION ALL
3 SELECT 125 videoid, 'a' userid FROM dual UNION ALL
4 SELECT 123 videoid, 'b' userid FROM dual UNION ALL
5 SELECT 123 videoid, 'b' userid FROM dual UNION ALL
6 SELECT 123 videoid, 'c' userid FROM dual
7 )
8 SELECT *
9 FROM (SELECT videoid, userid,
10 COUNT(*) over(PARTITION BY userid) nb_video
11 FROM table_play_list)
12 WHERE nb_video > 1;
VIDEOID USERID NB_VIDEO
---------- ------ ----------
123 a 2
125 a 2
123 b 2
123 b 2
The below will give users who have watched more than two different videos.
SELECT userid, count(distinct video_id)
FROM table_play_list
WHERE SOME CONDICTION
GROUP BY user_id
having count(distinct video_id) >2;
If you use Oracle PL/SQL you can use like this:
SELECT column1, column2
FROM
(
SELECT column1, column2, COUNT(column1)
OVER (PARTITION BY column1) AS cnt
FROM test
GROUP BY column1, column2
ORDER BY column1
)
WHERE cnt > 2
If you use standard SQL you can use like this:
SELECT column1, column2
FROM test
WHERE column1 IN
(
SELECT column1
FROM
(
SELECT column1, column2
FROM test
GROUP BY column1, column2
ORDER BY column1
)
GROUP BY column1
HAVING COUNT(column1) > 2
)
GROUP BY column1, column2
ORDER BY column1

How to convert code from Postgres to Oracle

I have a source table (T1):
ID1 | ID2
----------
1 | 2
1 | 5
4 | 7
7 | 8
9 | 1
I want to convert the data to this (T2):
ID1 | ID2 | LABEL
------------------
1 | 2 | 1
1 | 5 | 1
4 | 7 | 2
7 | 8 | 2
9 | 1 | 1
I found a solution for this in PostgreSQL:
with
recursive cte(id1, id2) as (
select id1, id2, 1 as level
from t
union all
select t.id1, cte.id2, cte.level + 1
from t join
cte
on t.id2 = cte.id1
)
select id1, id2,
dense_rank() over (order by grp) as label
from (select id1, id2,
least(min(id2) over (partition by id1), min(id1) over (partition by id2)) as grp,
level
from cte
) t
where level = 1;
I want to convert this code to Oracle. How I can convert this code from Postgres to Oracle?
Oracle 11.2 supports recursive CTEs. But it deviates from the standard in that the recursive keyword is not required (actually: must not be used). So if you remove the recursive keyword and get the definition of the CTE columns right the following should work. You also need to use something different than LEVEL as that is a reserved word either.
with cte (id1, id2, lvl) as (
select id1, id2, 1 as lvl
from t
union all
select t.id1, cte.id2, cte.lvl + 1
from t
join cte on t.id2 = cte.id1
)
select id1,
id2,
dense_rank() over (order by grp) as label
from (
select id1,
id2,
least(min(id2) over (partition by id1), min(id1) over (partition by id2)) as grp,
lvl
from cte
) t
where lvl = 1;
Here is an SQLFiddle example: http://sqlfiddle.com/#!4/deeb2/3
However I doubt that the original query was correct as you do not have a "starting condition" for the recursive CTE. The first part of the union retrieves all rows of the table. There should be a condition to restrict that to the "roots" of the hierarchy unless I'm mis-understanding the purpose of the query.
A recursive CTE can also be replaced with a CONNECT BY query, in your case this would be:
select id1, id2, level as lvl
from t
connect by prior id1 = id2;
You can combine that with the orginal query:
with cte (id1, id2, lvl) as (
select id1, id2, level as lvl
from t
connect by prior id1 = id2
)
select id1,
id2,
dense_rank() over (order by grp) as label
from (
select id1,
id2,
least(min(id2) over (partition by id1), min(id1) over (partition by id2)) as grp,
lvl
from cte
) t
where lvl = 1;
Although I think it should be the same, it seems that the hierarchy is traversed in a different order. Could be because the recursive CTE does a breadth first and the connect by a depth first recursion (or the other way round).
SQLFiddle example for the second version: http://sqlfiddle.com/#!4/deeb2/4

Resources