Oracle: transpose table - sql

I've got the following query
SELECT 1, 2 FROM DUAL
AND I'd like something like
SELECT TRANSPOSE(SELECT 1, 2 FROM DUAL)
Which outputs the same as
SELECT 1 FROM DUAL
UNION
SELECT 2 FROM DUAL
I'd like it to swap lines with columns.

Assuming this is Oracle 11, you can use UNPIVOT:
select no from
(SELECT 1 a, 2 b FROM DUAL) dummy
unpivot (no for col in (a as 'A', b as 'B'))

Using dbms_xmlgen.getxmltype and XMLTABLE:
SELECT *
FROM XMLTABLE('/ROWSET/ROW/*' passing dbms_xmlgen.getxmltype('SELECT 1, 2, 3 FROM DUAL')
COLUMNS val VARCHAR(100) PATH '.');
db<>fiddle demo
Advantage over unpivot - there is no need to specify column list in advance

If you don't have Oracle 11g, the best solution is the one you provided:
SELECT 1 FROM DUAL
UNION
SELECT 2 FROM DUAL

Related

How to extract a digit from number in oracle

please help with query how to extract digit '1' from below table using SQL in oracle.
Table
1000
1001
1010
0100
expected result ;
Table
1
11
11
1
You can use the simple string function TRANSLATE (which is faster than regular expressions):
SELECT TRANSLATE(value, '10', '1') AS result
FROM table_name
If you have more than binary digits then:
SELECT TRANSLATE(value, '1023456789.', '1') AS result
FROM table_name
Which, for the sample data:
CREATE TABLE table_name (value) AS
SELECT '1000' FROM DUAL UNION ALL
SELECT '1001' FROM DUAL UNION ALL
SELECT '1010' FROM DUAL UNION ALL
SELECT '0100' FROM DUAL;
Both output:
RESULT
1
11
11
1
db<>fiddle here
I expect you are giving us a simplified version of your problem? One way to achieve this is is using REGEXP_REPLACE to replace all characters but the character 1 with an empty space:
SELECT
REGEXP_REPLACE(YOUR_COLUMN,'[^1]','') AS DESIRED_RESULT
FROM YOUR_TABLE
You can check out this example: db<>fiddle
You can use regexp_replace:
WITH dat AS
(
SELECT '1000' AS numb FROM dual UNION ALL
SELECT '1001' FROM dual UNION ALL
SELECT '1010' FROM dual UNION ALL
SELECT '0100' FROM dual
)
SELECT regexp_replace(numb,'[^1]','')
FROM dat;

Oracle SQL order by Varchar2 with '_'

I've got a table with a varchar2 column. Sorting by that column did not give me the expected result:
with test (col) as
(select '_83_' from dual union all
select '_81_' from dual union all
select '4___' from dual union all
select '____' from dual
)
select * from test
order by col desc;
returns:
Col
1. '_83_'
2. '_81_'
3. '4___'
4. '____'
I did expect:
Col
1. '4___'
2. '_83_'
3. '_81_'
4. '____'
Can you explain this and help me to get '4___' to the start of my order by statement?
Edit Using Littlefoots statement for preproduceabillity...
Edit I am using Oracle 12c
Edit NLS_Sort is set to German language. This was the issue.
In my local database, NLS_SORT is set to BINARY so It is not reproducible.
WITH TEMO AS
(
SELECT '_83_' AS X FROM DUAL UNION ALL
SELECT '_81_' AS X FROM DUAL UNION ALL
SELECT '4___' AS X FROM DUAL UNION ALL
SELECT '____' AS X FROM DUAL
)
SELECT * FROM TEMO ORDER BY X DESC;
X
----
____
_83_
_81_
4___
But, after changing NLS_SORT from BINARY to GERMAN, the issue is reproduced.
ALTER SESSION SET NLS_SORT=GERMAN;
WITH TEMO AS
(
SELECT '_83_' AS X FROM DUAL UNION ALL
SELECT '_81_' AS X FROM DUAL UNION ALL
SELECT '4___' AS X FROM DUAL UNION ALL
SELECT '____' AS X FROM DUAL
)
SELECT * FROM TEMO ORDER BY X DESC;
X
----
_83_
_81_
4___
____
You can check the NLS values using the following table:
NLS_SESSION_PARAMETERS
NLS_DATABASE_PARAMETERS
so the conclusion is NLS_SORT parameter must be set accordingly because not everyone wants to sort using technique.
Default value of NLS_SORT is derived from NLS_LANGUAGE.
Refer oracle documents for more information about NLS_SORT.
Solution is to change NLS_SORT according to requirement.
Cheers!!
I don't understand the question. Yes, a comment would be more appropriate but I can't post this:
SQL> with test (col) as
2 (select '_83_' from dual union all
3 select '_81_' from dual union all
4 select '4___' from dual union all
5 select '____' from dual
6 )
7 select * from test
8 order by col;
COL
----
____
4___
_81_
_83_
SQL>
As you can see, my results differ from yours, i.e. I can't reproduce what you are saying. Could you explain it once again, please?
Using Oracle 11g R2:
Select Column1 From (
SELECT CAST( '_83_' AS varchar2(4) ) AS Column1 FROM dual
union all
SELECT CAST( '_81_' AS varchar2(4) ) AS Column1 FROM dual
union all
SELECT CAST( '4___' AS varchar2(4) ) AS Column1 FROM dual
union all
SELECT CAST( '____' AS varchar2(4) ) AS Column1 FROM dual
) A order by Column1 desc
Output:
____
_83_
_81_
4___
Personally I'd recommend Tejash's answer but you can also fudge it with something like:
SELECT * FROM table ORDER BY TRANSLATE(col, '_', 'z') desc;

SQL Query to Unpivot dependent column using oracle

i am trying to replicate below scenario using oracle sql query:
i have did it using union query , but in that query i am hitting same table multiple times, is there any alternate for this query?
Please note: col and val are depenedent on each other simillarly col_1 and val_1 are also dependent on each other
select id,col, val from tbl
union
select id,col_1, val_1 from tbl
Oracle 12C+ supports lateral joins, so you can do:
select t.id, v.col, v.val
from tbl t cross join lateral
(select t.col, t.val from dual union all
select t.col_1, t.val from dual
) v;
You can pivot and unpivot multiple columns with the PIVOT and UNPIVOT operators, you just need to know the correct syntax. In your case you want to UNPIVOT. You are losing some information in the way you show the desired output, and perhaps that's OK for your needs; in any case, below I include a column that shows the order of the pairs of columns. (A bit odd, showing 1 for COL/VAL and 2 for COL_1/VAL_1, but I assume those aren't your real column names anyway.) If you don't need the ORD column in the output, just drop it from the SELECT clause.
Note - COLUMN is an Oracle reserved word, it can't be a column name. I changed the column names to C and V in the output.
with
input(id, col, col_1, val, val_1) as (
select 1, 'ABC', 'DEF', 10, 20 from dual union all
select 2, 'GHI', 'JKL', 30, 40 from dual
)
select id, ord, c, v
from input
unpivot ( (c, v) for ord in ((col, val) as 1, (col_1, val_1) as 2))
;
ID ORD C V
---------- ---------- --- ----------
1 1 ABC 10
1 2 DEF 20
2 1 GHI 30
2 2 JKL 40

How can I add two columns sequentially (and not concatenate)?

I am trying to pull two tables from an Oracle SQL database, and want to join them sequentially, so they appear as if they are one list.
List one has items [1,2,3,4]
List two has items [a,b,c,d]
I want to output [1,2,3,4,a,b,c,d]
Any thoughts?
One option uses a UNION with a computed column:
SELECT val
FROM
(
SELECT val, 1 AS position FROM table1
UNION ALL
SELECT val, 2 AS position FROM table2
) t
ORDER BY
position, val;
Demo
Note that I assume that all data here is text. If not, e.g. the first table be numeric, then we would have to do a cast along the way. But, this is not the main focus of your question anyway.
SELECT id_1, value_column1 from table_1
UNION
SELECT id_2, value_column2 from table_2;
if the types of columns are different - make sure you cast/convert them to char() - the resulting type should be same.
https://docs.oracle.com/cd/B19306_01/server.102/b14200/queries004.htm
use union, i think 1,2,3 as numeric value that why converted it on varchar as for union you have to same data type
with t1 as (
select 1 as id from dual union all
select 2 from dual union all
select 3 from dual union all
select 4 from dual
), t2 as (
select 'a' as item from dual union all
select 'b' from dual union all
select 'c' from dual union all
select 'd' from dual
)
select cast(id as varchar(20)) as id from t1
union
select * from t2
demo
output
1
2
3
4
a
b
c
d

Which value(s) in WHERE CLAUSE LIST are not available in the table

I want to search which value(s) in MY WHERE CLAUSE LIST are not available in the table.
Table name is test
Column1
--------------
1
2
3
My query : I have a search list 2, 3, 4, 5 and I want to see which all are not in my database. When I query, I should get 4, 5 and NOT 1.
I do not want the list of values which are there in the table and not in where clause list(select * from test where column1 not in (2, 3, 4, 5)
Can someone please help ?
WITH my_list AS
(SELECT regexp_substr('2,3,4,5', '[^,]+', 1, LEVEL) AS search_val
FROM dual
CONNECT BY level <= regexp_count('2,3,4,5',',') + 1
)
SELECT *
FROM my_list
WHERE NOT EXISTS
(SELECT 'X' FROM YOUR_TABLE WHERE YOUR_COLUMN = search_val
);
Let's Convert the comma separated values into a view and then do what's needed.
You can do it as follows:
SELECT List FROM
(SELECT 2 as List
UNION
SELECT 3
UNION
SELECT 4
UNION
SELECT 5) T
WHERE List NOT IN
(SELECT Column1 FROM TableName)
In this case, I would do a simple select
select *
from test
where column1 in (2, 3, 4, 5)
and do the set operation in the host language (Java, C++, Perl, ...).
This seems far simpler than any SQL solution.
with cte as
(select 2 as val from dual
union all
select 3 from dual
union all
select 4 from dual
union all
select 5 from dual
union all
)
select * from cte as t1
where not exists
( select * from test as t2 where t1.val = t2.column1)
For a large number of values you might better create a temporary table, insert the rows and then use this instead of the common table expression.
Try below Query:
WITH MY_DATA_TABLE AS
(
SELECT regexp_substr('2,3,4,5', '[^,]+', 1, LEVEL) AS MY_DATA_VALUE
FROM dual
CONNECT BY level <= (length('2,3,4,5') - length(replace('2,3,4,5', ',')))
)
SELECT *
FROM MY_DATA_TABLE
WHERE NOT EXISTS
(SELECT 'TRUE' FROM TABLE_NAME WHERE TABLE_FIELD_VALUE = MY_DATA_VALUE
);
Your query with huge data would translate in ORACLE to:
WITH MY_DATA_TABLE AS
(
SELECT regexp_substr('1,4,5,8,9,12,13,14,20,39,43,48,51,54,55,57,61,65,68,75,78,80,81,82,91,92,96,99,‌​102,103,109,112,113,224,227,249,250,251,600,601,604,605,608,609,614,802', '[^,]+', 1, LEVEL) AS MY_DATA_VALUE
FROM dual
CONNECT BY level <= (length('1,4,5,8,9,12,13,14,20,39,43,48,51,54,55,57,61,65,68,75,78,80,81,82,91,92,96,99,‌​102,103,109,112,113,224,227,249,250,251,600,601,604,605,608,609,614,802') - length(replace('1,4,5,8,9,12,13,14,20,39,43,48,51,54,55,57,61,65,68,75,78,80,81,82,91,92,96,99,‌​102,103,109,112,113,224,227,249,250,251,600,601,604,605,608,609,614,802', ',')))
)
SELECT *
FROM MY_DATA_TABLE
WHERE NOT EXISTS
(SELECT 'TRUE' FROM TABLE_NAME WHERE TABLE_FIELD_VALUE = MY_DATA_VALUE
);