How to split two columns into two rows using oracle sql? - sql

for example I have a data below:
column1 column2 column3 column4 column5
A B 5 2 3
My desired table would be:
columnA
A
B
The condition to determine the splitting is if (column3 + column4)>5 otherwise no splitting.

union all:
select column1 as columnA from t where column3 + column4 > 5
union all
select column2 from t where column3 + column4 > 5 ;

I'm not sure I fully understood what you are looking for, but if you wan' to put a if, ele in the SELECT, you might wan't to use the CASE expression.
https://docs.oracle.com/cd/B19306_01/server.102/b14200/expressions004.htm

Use a LEFT JOIN (with join condition) or CROSS JOIN (no join condition) to a derived table that consists of 2 rows, then output the values via a case expression. Both approaches allow access to all columns for other conditions too.
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE TABLE1
(COLUMN1 VARCHAR2(1), COLUMN2 VARCHAR2(1), COLUMN3 INT, COLUMN4 INT, COLUMN5 INT)
;
INSERT ALL
INTO TABLE1 (COLUMN1, COLUMN2, COLUMN3, COLUMN4, COLUMN5)
VALUES ('A', 'B', 5, 2, 3)
INTO TABLE1 (COLUMN1, COLUMN2, COLUMN3, COLUMN4, COLUMN5)
VALUES ('C', 'D', 1, 1, 1)
SELECT * FROM DUAL
Query 1:
select
case when lj.rn = 1 then t.column1 else t.column2 end as columnA
, t.column1
, t.column2
, t.column3
, t.column4
, t.column5
from table1 t
left join ( select 1 as rn from dual union all select 2 from dual ) lj
on (column3 + column4) > 5
Results:
| COLUMNA | COLUMN1 | COLUMN2 | COLUMN3 | COLUMN4 | COLUMN5 |
|---------|---------|---------|---------|---------|---------|
| A | A | B | 5 | 2 | 3 |
| B | A | B | 5 | 2 | 3 |
| D | C | D | 1 | 1 | 1 |
Query 2:
select
case when cj.rn = 1 then t.column1 else t.column2 end as columnA
, t.column1
, t.column2
, t.column3
, t.column4
, t.column5
from table1 t
cross join ( select 1 as rn from dual union all select 2 from dual ) cj
Results:
| COLUMNA | COLUMN1 | COLUMN2 | COLUMN3 | COLUMN4 | COLUMN5 |
|---------|---------|---------|---------|---------|---------|
| A | A | B | 5 | 2 | 3 |
| B | A | B | 5 | 2 | 3 |
| C | C | D | 1 | 1 | 1 |
| D | C | D | 1 | 1 | 1 |

Suppose I have table test with sample data
column1 | column2 | column3 | column4 | column5
-------------------------------------------------------
A | B | 5 | 2 | 3
C | D | 1 | 1 | 1
E | F | 4 | 5 | 1
Script for above sample data:-
CREATE TABLE TEST
(
column1 VARCHAR2(10),
column2 VARCHAR2(10),
column3 NUMBER(2),
column4 NUMBER(2),
column5 NUMBER(2)
);
INSERT INTO TEST VALUES('A','B',5,2,3);
INSERT INTO TEST VALUES('C','D',1,1,1);
INSERT INTO TEST VALUES('E','F',4,5,1);
COMMIT;
Below query will give required output:-
WITH tmp AS
(SELECT (CASE
WHEN column3 + column4 > 5 THEN
column1||','||column2
ELSE
NULL
END) columna,
column1,column2,column3,column4,column5
FROM TEST)
SELECT regexp_substr(columna,'[^,]+',1,LEVEL) columna,
column1,column2,column3,column4,column5
FROM tmp
CONNECT BY LEVEL <= regexp_count(columna, ',') + 1
AND PRIOR column1 = column1
AND PRIOR dbms_random.random IS NOT NULL;
Output:
columnA | column1 | column2 | column3 | column4 | column5
-------------------------------------------------------------------
A | A | B | 5 | 2 | 3
B | A | B | 5 | 2 | 3
| C | D | 1 | 1 | 1
E | E | F | 4 | 5 | 1
F | E | F | 4 | 5 | 1

Related

Generate UUID which is same for a group of columns in SQL

Can someone pls suggest a way to write SQL query which would generate a unique UUID which would be same for a group of columns in amazon athena.
For example, i have a table like this, where i want to create a UUID for columns1, columns2 and columns3.
column1 | column2 | column3 | column 4
2016 | 101 | 1 | 25
2016 | 101 | 1 | 59
2017 | 105 | 2 | 57
2017 | 105 | 2 | 78
Output 1 must look like
ID | column1 | column2 | column3 | column 4
UUID-1 | 2016 | 101 | 1 | 25
UUID-1 | 2016 | 101 | 1 | 59
UUID-2 | 2017 | 105 | 2 | 57
UUID-2 | 2017 | 105 | 2 | 78
Output 2: should look like
ID | count |column1 | column2 | column3
UUID-1 | 2 |2016 | 101 | 1
UUID-2 | 2 |2017 | 105 | 2
I understand that grouping can be done on output 1 to generate output 2. Can someone suggest, how i can generate output 1 ?
Thanks.
You can try to use uuid() function.
SELECT uuid() id,
COUNT(*),
column1 ,
column2 ,
column3
FROM T
GROUP BY column1 ,
column2 ,
column3
EDIT
I saw you edit your question, you can try to use subquery and self join get output1
SELECT t1.*,t2.column4
FROM (
SELECT DISTINCT uuid() id,
column1 ,
column2 ,
column3
FROM T
) t1 INNER JOIN T t2
ON t1.column1 = t2.column1
AND t1.column2 = t2.column2
AND t1.column3 = t2.column3
another way you can try to use max window function to get only one GUID per column1,column2,column3 columns.
select max(id) over (partition by column1,column2,column3) as id,
column1,
column2,
column3,
column4
from
(
SELECT uuid() id,*
FROM T
) t1

Problem with creating a Procedure which should filter data

I need to create a procedure which filters data and insert it to a table.
I have 4 tables: (the keys are the id's)
table1:
id1
parameter1
parameter2
parameter3
table2:
id1
id2
table3:
id2
id3
value1
value2
value3
table4:
id2
id3
value1
value2
value3
I need to create a procedure which inserts to table 4 the values from table 3: value1, value2, value3, only if they are smaller than or equal to the parameters from table 1 (parameter1, parameter2, parameter3)
I've tried the next thing:
insert into table4 (
,Id2
,Id3
,value1
,value2
,value3
)
select
,Id2
,Id3
,value1
,value2
,value3
FROM table1
LEFT JOIN table2 ON table1.id1 = table2.id1
LEFT JOIN table3 ON table2.id2 = table3.id3
WHERE table3.value1 <= table1.parameter1
and table3.value2 <= table1.parameter2
and table3.value3 <= table1.parameter3
But each run, 3 new rows are inserted to table4 with different values and wrong values (they are bigger than the parameters).
What am I doing wrong? Should I create the procedure with IF statement instead? How to make it right?
I've added an example.
As you can see, the new table: table 4, has only 2 rows, because the value of 'value 2' in table3 (value 2= 12) is greater than 'parameter2' (parameter2= 11) (from table 1)
table1:
Id1 | Parameter1 | Parameter2 | Parameter3 |
=====+============+=============+============+
1 | 1 | 2 | 3 |
2 | 10 | ** 11 ** | 12 |
3 | 10 | 15 | 16 |
table2:
Id1 | Id2 |
=====+=====+
1 | 4 |
2 | 5 |
3 | 6 |
table3:
Id2 | Id3 | Value1| Value2| Value3|
=====+=====+========+=======+=======+
4 | 7 | 1 | 2 | 3 |
5 | 8 | 10 |** 12**| 12 |
6 | 9 | 1 | 2 | 3 |
The new table (table 4) should be:
table4:
Id2 | Id3 | Value1| Value2| Value3|
=====+=====+========+=======+=======+
4 | 7 | 1 | 2 | 3 |
6 | 9 | 1 | 2 | 3 |
If you use table3 as the table you select from, you can use joins with the other tables as filters when inserting. Try this (for SQL Server):
INSERT INTO table4 (
id2
,id3
,value1
,value2
,value3
)
SELECT
t3.id2
,t3.id3
,t3.value1
,t3.value2
,t3.value3
FROM table3 t3
JOIN table2 t2 on t3.id2 = t2.id2
JOIN table1 t1 on t2.id1 = t1.id
and t3.value1 <= t1.parameter1
and t3.value2 <= t1.parameter2
and t3.value3 <= t1.parameter3

SQL copy value from once column to another based on a condition

There are 4 columns in my SQL table:
+--------+----------+---------+--------+-----------+
|Column1 |Column2 |Column3 |Column4 |Column5 |
+--------+----------+---------+--------+-----------+
| 1 | abc | def | | 34654 |
| 2 | def | abc | | 798798 |
+--------+----------+---------+--------+-----------+
Goal is check if Column3 is in Column2, if it matches then fill Column4 with the respective value of Column1.
For example, "def" of Column3 matches "def" of Column2, so Column4 should be 2.
Desired output:
+--------+----------+---------+--------+-----------+
|Column1 |Column2 |Column3 |Column4 |Column5 |
+--------+----------+---------+--------+-----------+
| 1 | abc | def | 2 | 34654 |
| 2 | def | abc | 1 | 798798 |
+--------+----------+---------+--------+-----------+
I tried doing join on one of the tables like this:
SELECT a.Column1
, a.Column2
, a.Column3
, b.Column1 as Column4 FROM "table" a
LEFT JOIN "table" b on lower(a.Column3) = lower(b.Column2)
This creates a new Column4 when in my table Column4 already exists. I am doing UNION ALL of many tables and I need all my columns (32 in total) as the output.
How can I achieve this using SQL query?
in a SELECT
SELECT a.Column1
, a.Column2
, a.Column3
, case when Column2 = Column3
then Column1
else Column4 -- keep same value
end as Column4
, a.Column5
FROM "table" a
in an UPDATE
update "table"
set Column4 = case when Column2 = Column3
then Column1
else Column4 -- keep same value
end

select SQL rows depending on non-identical results of a query

I am trying to select the columns which is relevant without knowing in advance which ones
I do a:
select *
from table
where id = '1'
the result i get is maybe 10 rows and 100+ columns
|id | column1 | column2 | column3 | column4 | column5 |....
| 1 | a | b | c | d | e |....
| 1 | a | XXX | c | d | e |....
| 1 | a | b | c | YYY | e |....
| 1 | a | b | c | d | e |....
For every row, one (or more) of the columns value is different, but i dont know which one(s)
is there any way i can create a temp table with the first query and do a sub query to display only one columns which doesnt have the same value in all the rows?
so the result would look like this:
|id | column2 | column4 |
| 1 | b | d |
| 1 | XXX | d |
| 1 | b | YYY |
| 1 | b | d |
since column 2 and 4 were the ones with non identical data these are the ones I want to see.
As already mentioned, this would require dynamic sql.
Maybe this will help you:
CREATE TABLE Column_Relevance
SELECT id,
COUNT(DISTINCT(column_1))/COUNT(*) AS relevance_column_1,
COUNT(DISTINCT(column_2))/COUNT(*) AS relevance_column_2,
COUNT(DISTINCT(column_3))/COUNT(*) AS relevance_column_3,
# AND SO ON....
GROUP BY id;
All relevance_columns with value < 1 indicate different values for the columns. You can build the whole statement in excel in a few minutes.
Once the table is created, add another column and create a select statement based on the column relevance (e.g. select if(relevance_column_1<1, column_1, else 'ignore') as column_1. This will return the string 'ignore' for all columns, that don't have distinct values.
This is far from perfect but maybe it helps you a little.
Here is a way you could use some aggregation to help. You said you have nearly 100 columns so this could take some effort to create but once it is done it would be fine. And this is just for analysis. You could utilize sys.columns to build the code for you but then we are back in the land of dynamic sql.
declare #Something table
(
ID int
, Column1 varchar(10)
, Column2 varchar(10)
, Column3 varchar(10)
, Column4 varchar(10)
, Column5 varchar(10)
)
insert #Something
values
(1, 'a', 'b', 'c', ' d ', 'e')
, (1, 'a', 'XXX', 'c', ' d ', 'e')
, (1, 'a', 'b', 'c', 'YYY', 'e')
, (1, 'a', 'b', 'c', ' d ', 'e')
;
with MinMax as
(
select ID
, MIN(Column1) as Col1Min
, MAX(Column1) as Col1Max
, MIN(Column2) as Col2Min
, MAX(Column2) as Col2Max
, MIN(Column3) as Col3Min
, MAX(Column3) as Col3Max
, MIN(Column4) as Col4Min
, MAX(Column4) as Col4Max
, MIN(Column5) as Col5Min
, MAX(Column5) as Col5Max
from #Something
group by ID
)
select s.ID
, Column1 = case when mm.Col1Max = mm.Col1Min then '' else s.Column1 end
, Column2 = case when mm.Col2Max = mm.Col2Min then '' else s.Column2 end
, Column3 = case when mm.Col3Max = mm.Col3Min then '' else s.Column3 end
, Column4 = case when mm.Col4Max = mm.Col4Min then '' else s.Column4 end
, Column5 = case when mm.Col5Max = mm.Col5Min then '' else s.Column5 end
from #Something s
join MinMax mm on mm.ID = s.ID
Have you tried using distinct ? It returns only unique rows:
select *
from table
where id = '1'
|id | column2 | column4 |
| 1 | a | a |
| 1 | a | a |
| 1 | b | d |
| 1 | b | d |
select distinct * from table where id= '1'
|id | column2 | column4 |
| 1 | a | a |
| 1 | b | d |
I hope this helps you.

SQL: Inner join with top 2 rows with second table from on condition

Hi I am now trying to join 2 table with only 2 rows from second table join to first table.
For example, I have following 2 tables:
**Table A**
Column1 | Column2 | Column3
A | B | 30
A | C | 50
A | D | 25
**Table B**
Column4 | Column5
B | 35
B | 90
B | 65
B | 80
B | 85
B | 40
C | 100
C | 60
C | 70
C | 65
Here is example of my normal query:
select *
from
(
select *
from A
where Column1 = 'A' and (Column2 = 'B' or Column2 = 'C')
order by Column2, Column3
) A
inner join
(
select *
from B
where (Column4 = 'B' or Column4 = 'C')
order by Column5
) B
on (A.Column2 = B.Column4 and ((B.Column5 - A.Column3) > 30))
The Result should look like:
**Result:**
Column1 | Column2 | Column3 | Column4 | Column5
A | B | 30 | B | 65
A | B | 30 | B | 80
A | B | 30 | B | 85
A | B | 30 | B | 90
A | C | 50 | C | 100
However, the result that I want is to join only 2 row from second table result only. The expected result should be:
**Expected Result:**
Column1 | Column2 | Column3 | Column4 | Column5
A | B | 30 | B | 65
A | B | 30 | B | 80
A | C | 50 | C | 100
Do anyone have idea of how to create such sql statement? Thank you.
You could use row_number() to limit the number of rows. The example assumes that (Column1, Column2, Column3) is unique. If table A has a primary key, use that instead.
select *
from (
select Column1
, Column2
, Column3
, Column4
, Column5
, row_number() over (partition by Column1, Column2, Column3
order by Column5 - Column3 desc) as rn
from A
join B
on A.Column2 = B.Column4
where Column1 = 'A'
and Column2 in ('B', 'C')
and Column5 - Column3 > 30
) SubQueryAlias
where rn < 2
See example at SQL Fiddle.
A good start would be to write more simple SQL without the inline views:
select *
from A inner join
B on (A.Column2 = B.Column4)
where A.Column1 = 'A' and
A.Column2 in ('B','C') and
(B.Column5 - A.Column3) > 30)
Try using a CTE
WITH Top2Rows AS (
SELECT TOP 2 *
FROM TableB
WHERE ([ADD CONSTRAINTS])
)
SELECT *
FROM TableA a
JOIN Top2Rows r ON a.ID = b.ID
WHERE ([ADD CONSTRAINTS])