How to get the following result? - oracle

How to get the following result ?
Input : -
t1
--------------
col1 col2 col3
--------------
101, abc, 100
101, xyz, 200
101, rst, 300
-------------
Output : -
101 abc 100 xyz 200 rst 300

Please try:
SELECT col1, replace(wm_concat(col2||col3),',', '') FROM t1 GROUP BY col1;
or
SELECT col1, (SELECT XMLAGG(xmlelement(X, X1.col2||col3)order by X1.col2).extract('//text()')
FROM t1 X1 WHERE X1.col1=X.col1)
FROM t1 X

This works with 11g and maintains the order of items.
select LISTAGG (code, ' ') WITHIN GROUP (ORDER BY rn, coln)
from(
select code, min(rn) as rn, min(coln) as coln
from(
select col1 as code, rownum rn, 1 as coln from t order by col1, col3
union all
select col2 as code, rownum rn, 2 as coln from t order by col1, col3
union all
select col3 as code, rownum rn, 3 as coln from t order by col1, col3
)
group by code
)

Try with
select col1 || ' ' || listagg( col2 || ' ' || col3, ' ' ) within group ( order by COL3 )
from t1
group by col1;

Related

row number based on unique column value in oralce?

I do need to implement a oracle sql to have row number defined as below:
row_num, column1, column2, cloumn3
1, ABC, 123, a1
1, ABC, 125, a2
2, ABD, 123, a3
2, ABD, 124, a4
2, ABD, 125, a5
3, ABE, 123, a1
Here I defined row number based on unique value of column1.
Can any one help me to write oracle sql to define row number in this way?
Thanks
Venkat
You need the DENSE_RANK() analytic function:
WITH your_table AS (SELECT 'ABC' col1, 123 col2, 'a1' col3 FROM dual UNION ALL
SELECT 'ABC' col1, 125 col2, 'a2' col3 FROM dual UNION ALL
SELECT 'ABD' col1, 123 col2, 'a3' col3 FROM dual UNION ALL
SELECT 'ABD' col1, 124 col2, 'a4' col3 FROM dual UNION ALL
SELECT 'ABD' col1, 125 col2, 'a5' col3 FROM dual UNION ALL
SELECT 'ABE' col1, 123 col2, 'a1' col3 FROM dual)
-- end of subquery mimicking your_table with data in; See SQL below:
SELECT dense_rank() OVER (ORDER BY col1) row_num,
col1,
col2,
col3
FROM your_table
ORDER BY col1, col2, col3;
ROW_NUM COL1 COL2 COL3
---------- ---- ---------- ----
1 ABC 123 a1
1 ABC 125 a2
2 ABD 123 a3
2 ABD 124 a4
2 ABD 125 a5
3 ABE 123 a1
DENSE_RANK() is similar to RANK() in that it will assign tied rows the same rank (that is, rows that have the same values in the columns being ordered - in your case, col1), but unlike RANK(), DENSE_RANK() won't skip rank numbers.
You can use this as well, but I forgot about dense rank. So Boneist's answer is better.
select rn.row_num , t.* from
(select column1,row_number() over (order by column1) as row_num from
(select distinct column1 column1 from tbl23) )rn
inner join tbl23 t
on rn.column1=t.column1

Generate difference between 2 tables listing columns from both tables

Have 2 tables with same columns and want to generate the difference between the tables and want to show the difference listing all columns from both tables
example:
select a.*,b.* from (
(
select a.col1,a.col2 from
(select col1, col2 from table1 minus select col1, col2 from table2) as a
)
union
(
select b.col1, b.col2 from
(select col1, col2 from table2 minus select col1, col2 from table2) as b
)
)
The result should be
a.col1 a.col2 b.col1 b.col2
a.FName a.ZipCode b.FName b.ZipCode
John <same value> Jane <same value as A>
Alpha 1234 Beta 2345
My query returns exception that it is missing R parenthesis after the 1st minus keyword
I think you are trying to find rows from table a which are missing in table b and rows in table b which are missing from table a. However, there is no point in joining these two sets. Try the following query and see if it works for you.
SELECT col1, col2, 'Missing from table 2' title
FROM
(
SELECT col1,
col2
FROM table1
MINUS
SELECT col1,
col2
FROM table2
)
UNION ALL
SELECT col1, col2, 'Missing from table 1' title
FROM
(
SELECT col1,
col2
FROM table2
MINUS
SELECT col1,
col2
FROM table1
)

how to find the value which is common in a column for all the values in other column?

If i'm having a table like this.
col1 col2 col3
1 2 3
1 3 2
1 2 1
1 2 2
1 2 3
I want only the col2 values which appears for all three values(1,2,3) in col3
col2
2
How to get result like this guys?
select col2
from your_table
group by col2
having count(distinct col3) = (select count(distinct col3) from your_table)
Assuming that 1, 2 and 3 are the only acceptable values for col3 (and that the column is not null), then you could do it like this:
with sample_data as (select 1 col1, 2 col2, 3 col3 from dual union all
select 1 col1, 3 col2, 2 col3 from dual union all
select 1 col1, 2 col2, 1 col3 from dual union all
select 1 col1, 2 col2, 2 col3 from dual union all
select 1 col1, 2 col2, 3 col3 from dual),
res as (select col1,
col2,
col3,
count(distinct col3) over (partition by col1, col2) cnt_distinct_col3
from sample_data)
select col1,
col2,
col3
from res
where cnt_distinct_col3 = 3;
COL1 COL2 COL3
---------- ---------- ----------
1 2 1
1 2 2
1 2 3
1 2 3
I wasn't sure from your sample_data if you were just going from col2, or whether it was col1 + col2; eg, if the sample data was:
COL1 COL2 COL3
---------- ---------- ----------
1 2 3
1 3 2
1 2 1
1 2 2
1 2 3
2 3 1
2 3 3
Would you expect to see col2 = 2 and col2 = 3 rows returned, or would you only expect to see (col1, col2) = (1, 2) rows returned?
I have assumed the latter, but if it's the former, it's just a case of taking col1 out of the partition clause in the analytic function. And then, of course, changing the select to "select distinct col2".
So, depending on how you want the answers displayed, I think my query works for the situations where you want to show col1 in the results (ie. unfiltered) and when you want to filter by a specific col1 value, e.g;
with sample_data as (select 1 col1, 2 col2, 3 col3 from dual union all
select 1 col1, 3 col2, 2 col3 from dual union all
select 1 col1, 2 col2, 1 col3 from dual union all
select 1 col1, 2 col2, 2 col3 from dual union all
select 1 col1, 2 col2, 3 col3 from dual union all
select 2 col1, 3 col2, 1 col3 from dual union all
select 2 col1, 3 col2, 2 col3 from dual union all
select 2 col1, 3 col2, 3 col3 from dual union all
select 2 col1, 2 col2, 1 col3 from dual union all
select 3 col1, 1 col2, 2 col3 from dual union all
select 3 col1, 1 col2, 3 col3 from dual),
res as (select col1,
col2,
col3,
count(distinct col3) over (partition by col1, col2) cnt_distinct_col3
from sample_data)
select distinct col1,
col2
from res
where cnt_distinct_col3 = 3;
COL1 COL2
---------- ----------
2 3
1 2
with sample_data as (select 1 col1, 2 col2, 3 col3 from dual union all
select 1 col1, 3 col2, 2 col3 from dual union all
select 1 col1, 2 col2, 1 col3 from dual union all
select 1 col1, 2 col2, 2 col3 from dual union all
select 1 col1, 2 col2, 3 col3 from dual union all
select 2 col1, 3 col2, 1 col3 from dual union all
select 2 col1, 3 col2, 2 col3 from dual union all
select 2 col1, 3 col2, 3 col3 from dual union all
select 2 col1, 2 col2, 1 col3 from dual union all
select 3 col1, 1 col2, 2 col3 from dual union all
select 3 col1, 1 col2, 3 col3 from dual),
res as (select col1,
col2,
col3,
count(distinct col3) over (partition by col1, col2) cnt_distinct_col3
from sample_data)
select distinct col2
from res
where cnt_distinct_col3 = 3
and col1 = 1;
COL2
----------
2
Ok, I think this is what you're after:
with sample_data as (select 1 col1, 2 col2, 3 col3 from dual union all
select 1 col1, 3 col2, 2 col3 from dual union all
select 1 col1, 2 col2, 1 col3 from dual union all
select 1 col1, 2 col2, 2 col3 from dual union all
select 1 col1, 2 col2, 3 col3 from dual union all
select 2 col1, 3 col2, 1 col3 from dual union all
select 2 col1, 3 col2, 2 col3 from dual union all
select 2 col1, 3 col2, 3 col3 from dual union all
select 2 col1, 2 col2, 1 col3 from dual union all
select 3 col1, 1 col2, 2 col3 from dual union all
select 3 col1, 1 col2, 3 col3 from dual),
res as (select col1,
col2,
col3,
count(distinct col3) over (partition by col1, col2) cnt_distinct_col3_per_col1col2,
count(distinct col3) over (partition by col1) cnt_distinct_col3_per_col1
from sample_data)
select distinct col2
from res
where cnt_distinct_col3_per_col1col2 = cnt_distinct_col3_per_col1
and col1 = 1;
COL2
----------
2
The way this works is:
find the number of distinct col3 values for each col1 value. (So in the example above, for col1 = 1, there are 3 different col3 values.)
find the number of distinct col3 values for each (col1, col2) pairing. (So in the example above, for (col1, col2) = (1, 2) there are 3 different col3 values, and for (col1, col2) = (1, 3) there is only 1)
select the rows where these two numbers match. (So from the above example, only (col1, col2) = (1, 2) has the same number of distinct values (3) as col1 = 1 does (3).

SQL query to get grouped sums and concatenated lists, preferably without using functions

I have a table like
colA colB colC
A 10 1
A 20 2
A 30 3
B 10 1
B 20 2
I want an output like this
ColA colB colC
A 60 1,2,3
B 30 1,2
Can someone tell me how to do it with and without using functions, and in PL/SQL?
Here is sql you needed.
Note : it will only run on oracle 11g R2 onwards.
with tab as(
select 'A' col1,10 col2,1 col3 from dual union all
select 'A' col1,20 col2,2 col3 from dual union all
select 'A' col1,30 col2,3 col3 from dual union all
select 'B' col1,10 col2,1 col3 from dual union all
select 'B' col1,20 col2,2 col3 from dual )
select col1, sum(col2),listagg(col3,',') WITHIN GROUP (ORDER BY col3) AS col3_list
from tab group by col1
Assume your table name is tab
with tab1(col1, col2) as (
select colA, sum(colB)
from tab group by colA
),
tab2(col1, col2) as (
select colA, LISTAGG(TO_CHAR(colC),',')
WITHIN GROUP (ORDER BY colC)
from tab group by colA
)
select a.col1, a.col2, b.col2
from tab1 a, tab2 b
where a.col1 = b.col1
OutPut:
COL1 COL2 COL2
A 60 1,2,3
B 30 1,2
For more information about LISTAGG link
This link explains about multiple with clause
Or simply;
select colA, sum(colB) colB,LISTAGG(TO_CHAR(colC),',')
WITHIN GROUP (ORDER BY colC)
from tab group by colA
Probably this may the easiest solution syntactically :)
SELECT COLA,
SUM(COLB),
WMSYS.WM_CONCAT(COLC)
FROM
(SELECT 'A' cola,10 AS colb,1 AS colc FROM dual
UNION
SELECT 'A' cola,20 AS colb,2 AS colc FROM dual
UNION
SELECT 'A' cola,30 AS colb,3 AS colc FROM dual
UNION
SELECT 'B' cola,10 AS colb,1 AS colc FROM dual
UNION
SELECT 'B' cola,20 AS colb,2 AS colc FROM dual
)
GROUP BY COLA ;
OUTPUT
COLA SUM(COLB) WMSYS.WM_CONCAT(COLC)
A 60 1,2,3
B 30 1,2

Oracle - Is it possible to "set" values inside case statement during update as below?

Is it possible to "set" values inside case statement during update as below ?
UPDATE TABLE1
CASE WHEN COL1 = 'A' THEN SET COL2 = 10, COL3 = 20, COL4 = 30
WHEN COL1 IN ('B','N') THEN SET COL2 = 1, COL3 = 5, COL4 = 7
WHEN COL1 = 'D' THEN SET COL2 = 11, COL3 = 13, COL4 = 17
ELSE SET COL2 = 0, COL3 = 0, COL4 = 0
END;
The corresponding valid syntax would be like this.
UPDATE TABLE1 SET
COL2 = (CASE WHEN COL1 = 'A' THEN 10
WHEN COL1 IN ('B','N') THEN 1
WHEN COL1 = 'D' THEN 11
ELSE 0
END),
COL3 = (CASE WHEN COL1 = 'A' THEN 20
WHEN COL1 IN ('B','N') THEN 5
WHEN COL1 = 'D' THEN 13
ELSE 0
END),
COL4 = (CASE WHEN COL1 = 'A' THEN 30
WHEN COL1 IN ('B','N') THEN 7
WHEN COL1 = 'D' THEN 17
ELSE 0
END);
Looks like you're trying to do a MERGE, with one exception. You can update the table in a single merge statement as follows, except your logic to update all non-matching rows to 0's.
SQL> create table tab1
(
col1 varchar2(10),
col2 number,
col3 number,
col4 number,
merge_flag char(1)
)
Table created.
SQL> insert into tab1 values ('A', 10,11,12,null)
1 row created.
SQL> insert into tab1 values ('B', 20,21,22,null)
1 row created.
SQL> insert into tab1 values ('C', 30,31,32,null)
1 row created.
SQL> commit
Commit complete.
SQL> select * from tab1
COL1 COL2 COL3 COL4 MERGE_FLAG
---------- ---------- ---------- ---------- ----------
A 10 11 12
B 20 21 22
C 30 31 32
3 rows selected.
SQL> merge into tab1 t
using (
select 'A' as col1, 10 as col2, 20 as col3, 30 as col4 from dual
union
select 'B' as col1, 1 as col2, 5 as col3, 7 as col4 from dual
union
select 'N' as col1, 1 as col2, 5 as col3, 7 as col4 from dual
union
select 'D' as col1, 11 as col2, 13 as col3, 17 as col4 from dual
) x
on (t.col1 = x.col1)
when matched then
update set t.col2 = x.col2, t.col3 = x.col3, t.col4 = x.col4, t.merge_flag = 'X'
Merge successfully completed.
SQL> commit
Commit complete.
SQL> select * from tab1
COL1 COL2 COL3 COL4 MERGE_FLAG
---------- ---------- ---------- ---------- ----------
A 10 20 30 X
B 1 5 7 X
C 30 31 32
3 rows selected.
You could run a single update after the merge to change all non matching rows with 0.
In order to do this via case, you would have to repeat the case for each field (as demonstrated by #MaheswaranRavisankar). That's just the way case works. An alternative would be to fabricate a sub-query that provides the same results. While this is longer, it does group related values together, which may be more readable/easier to maintain.
Given the need to set all non-matching values to zero, I would solve that by setting all values to zero first, then updating the matches the appropriate value.
UPDATE table1
SET col2 = 0, col3 = 0, col4 = 0;
UPDATE table1
SET (col2, col3, col4) =
(SELECT a.col2, a.col3, a.col4
FROM (SELECT 'A' AS col1,
10 AS col2,
20 AS col3,
30 AS col4
FROM DUAL
UNION ALL
SELECT 'B' AS col1,
5 AS col2,
5 AS col3,
7 AS col4
FROM DUAL
UNION ALL
SELECT 'N' AS col1,
5 AS col2,
5 AS col3,
7 AS col4
FROM DUAL
UNION ALL
SELECT 'D' AS col1,
13 AS col2,
7 AS col3,
17 AS col4
FROM DUAL) a
WHERE a.col1 = table1.col1);
This also hints at another option: perhaps you should consider creating a table with these values, rather than embedding them in the SQL.

Resources