display multiple column records in one column in oracle - 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

Related

combine multiple rows result in single row based on one column value

I i want to combine multiple rows result into single row based on one column called type.
Ex say suppose i have below result from my query .
seqnum type name
456 SH Google2
456 CN transwork
123 SH partyshipper
123 CN consignee
Actual result i want is something like below table
seqnum consigneename shippername
456 transwork Google2
123 consignee partyshipper
Basically i want to get result like consignee name when type is CN and shipper name is when type is SH if its not both then i can add extra column with name just like otherparty.
I can get result and iterate result set and set value of object. but i think this will be better if we get formatted result in query only.can some one help in in getting this.
Thanks for the help.
Something like this usually helps; lines #1 - 7 represent your sample data. Code you need begins at line #8.
SQL> with test (seqnum, type, name) as
2 (select 456, 'SH', 'Google2' from dual union all
3 select 456, 'CN', 'transwork' from dual union all
4 select 123, 'SH', 'partyshipper' from dual union all
5 select 123, 'CN', 'consignee' from dual union all
6 select 999, 'XX', 'littlefoot' from dual
7 )
8 select seqnum,
9 max(case when type = 'CN' then name end) consigneename,
10 max(case when type = 'SH' then name end) shipppername,
11 max(case when type not in ('CN', 'SH') then name end) otherparty
12 from test
13 group by seqnum;
SEQNUM CONSIGNEENAM SHIPPPERNAME OTHERPARTY
---------- ------------ ------------ ------------
123 consignee partyshipper
999 littlefoot
456 transwork Google2
SQL>
Borrowing the query from #Littlefoot. You may also use PIVOT for this getting the expected result.
with test (seqnum, type, name) as
(select 456, 'SH', 'Google2' from dual union all
select 456, 'CN', 'transwork' from dual union all
select 123, 'SH', 'partyshipper' from dual union all
select 123, 'CN', 'consignee' from dual union all
select 999, 'OT', 'littlefoot' from dual
)
select * from test
pivot (
min(name) for type in
(
'SH' shippingname
, 'CN' consigneename
, 'OT' someother
)
)
;
SEQNUM SHIPPINGNAME CONSIGNEENAM SOMEOTHER
---------- ------------ ------------ ------------
999 littlefoot
456 Google2 transwork
123 partyshipper consignee
I'd self join the table and filter different types in each side of the join:
SELECT COALESCE(c.seqnum, s.seqnum) AS seqnum,
COALESCE(c.name, 'other') AS consigneename,
COALESCE(s.name, 'other') AS shippername
FROM (SELECT *
FROM mytable
WHERE type = 'CN') c
FULL OUTER JOIN (SELECT *
FROM mytable
WHERE type = 'SN') s ON c.seqnum = s.seqnum

How to perform union on table when table consists of different column name but datatype is same?

How do I perform union on two tables, when table consists of different column name but datatype is the same. Table1(id, name, location) and table2(id, name, address). Here location(varchar) and address(varchar).
I have tried the following but it returns like this when I run the query:
Query :
SELECT id, name, location, null as address FROM T1
union
SELECT id, name, address, null as location FROM T2;
**output** :
ID NAME LOCATION ADDRESS
1 1 AA NED NULL
2 2 BB AUB NULL
3 2 BB MUN NULL
4 3 CC PUNE NULL
but I need output like below :
ID NAME LOCATION ADDRESS
1 1 AA NED NULL
2 2 BB AUB NULL
3 2 BB NULL MUN
4 3 CC NULL PUNE
The way I see it:
SELECT id, name, location, null as address FROM T1
union
SELECT id, name, null as location, address FROM T2;

Order by: Special characters before ABC

I have this sql:
SELECT -1 AS ID, '(None)' AS NAME
FROM TABLE_1 WHERE ID=1
UNION
SELECT ID, NAME
FROM TABLE_2
ORDER BY 2
Table data:
ID | NAME
1 | Direct
2 | Personal
3 | Etc
So if i execute this sql in Oracle 10 it returns these:
Result:
ID | NAME
1 | Direct
3 | Etc
-1 | (None)
2 | Personal
How is it possible to sort the "(None)" always to the top?
If i use
' (None) ' as Name
instead of
'(None)' as Name
It works, because the space before the (None), but that is not a solution.
You can add a dummy column ORDER_COL and then order on that column
select ID, NAME from
(
SELECT -1 AS ID, '(None)' AS NAME, 1 as ORDER_COL FROM TABLE_1 WHERE ID=1
UNION
SELECT ID, NAME, 2 as ORDER_COL FROM TABLE_2
)
order by ORDER_COL, NAME;
Try this. NULLS LAST is the default for ascending order in Oracle. make it NULLS FIRST for '(None)'. Also, use UNION ALL as UNION removes duplicates and is less efficient.
SELECT *
FROM (
SELECT -1 AS ID
,'(None)' AS NAME
FROM TABLE_1
WHERE ID = 1
UNION ALL
SELECT ID
,NAME
FROM TABLE_2
)
ORDER BY CASE
WHEN NAME = '(None)'
THEN NULL
ELSE NAME -- or id if you want
END NULLS FIRST;

Only join two columns when it is not null in one table oracle

I have a table a
ID | Name | City
1 |Jack | Null
2 |Tom | Null
And table b
ID | Name | City
1 |Jack | Dever
2 |Tom | Dallas
I need to write a query to join these two tables by id, name and city if they are not null in table a. But any of these three column could be null for each row.
I wrote one below but the performance is bad when data grows
Select * from a, b
Where (a.id is not null and a.id=b.id or a.id is null) and
(a.name is not null and a.name=b.name or a.name is null) and
(a.city is not null and a.city=b.city or a.city is null)
Basically, I need to join on the column when it is not null in table a.
Could you shed some light on this?
Thanks a lot!
ATTEMPT I:
Would this be what you need? It seems to do what I can read out from your question.
with a as (select 1 id, 'Jack' name, null city from dual
union all
select 2 id, 'Tom' name, null city from dual
union all
select 3 id, 'Mike' name, 'Miami' city from dual)
,b as (select 1 id, 'Jack' name, 'Dever' city from dual
union all
select 2 id, 'Tom' name, 'Dallas' city from dual
union all
select 3 id, 'Mike' name, 'Boise' city from dual)
select b.*
from b
left outer join a
on a.id = b.id
and a.name = b.name
where b.city = nvl(a.city, b.city);
If not, please advisa as to what would need to change in the result or possibly in the indata.
UPDATE I:
To allow all columns to have the possibility of being null, this could be one way of doing it. I've added testdata for the conditions I think your are describing. It gives the result I think you are looking for.
with a as (select 1 id, 'Jack' name, null city from dual
union all
select 2 id, 'Tom' name, null city from dual
union all
select 3 id, 'Mike' name, 'Miami' city from dual
union all
select 4 id, 'Don' name, null city from dual
union all
select 5 id, null name, 'London' city from dual
union all
select null id, 'Erin' name, 'Berlin' city from dual
)
,b as (select 1 id, 'Jack' name, 'Dever' city from dual
union all
select 2 id, 'Tom' name, 'Dallas' city from dual
union all
select 3 id, 'Mike' name, 'Boise' city from dual
union all
select 4 id, 'Don' name, 'Dover' city from dual
union all
select 5 id, 'Lis' name, 'London' city from dual
union all
select 6 id, 'Erin' name, 'Berlin' city from dual
)
select b.*, a.*
from b
inner join a
on b.id = nvl(a.id, b.id)
and b.name = nvl(a.name, b.name)
and b.city = nvl(a.city, b.city)
order by 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

Resources