Creating resultset based on column name defined in another table in Oracle - sql

In Oracle database, I have a table DATA_DUMP_TABLE which has generic column names
id column1 column2 column3 column4 column5 def_id
1 John Doe null null null 1
2 Tom Baker null null null 1
Then I have a metadata table COLUMN_DEF which defines the data column names. It could vary based on the definition id. Say in this case I just want to map the first 2 columns.
def_id mapped_column mapped_column_val`
1 column1 First Name
1 column2 Last Name
The resultset I am expecting is based on the mapped_column_val from COLUMN_DEF table
So, in this case the resultset would look like this
id First Name Last Name
1 John Doe
2 Tom Baker
How do I achieve this in oracle, whether this could be done via SQL or I have to use advance packages? Any help would be appreciated.

It Works with sql server.
DECLARE #new_names as nvarchar(MAX)
DECLARE #sql as nvarchar(MAX)
SELECT #new_names = STRING_AGG('[' + MAPPED_COLUMN_VAL + ']', ',') FROM COLUMN_DEF
SET #sql = 'SELECT * FROM (
SELECT t.ID, t.COLUMN_VALUES, t.DEF_ID, c.MAPPED_COLUMN_VAL FROM (
SELECT ID, COLUMN_NAME, COLUMN_VALUES, DEF_ID
FROM
(SELECT * FROM DUMP_DATA) d
UNPIVOT
(
COLUMN_VALUES FOR COLUMN_NAME IN
(COLUMN1, COLUMN2, COLUMN3, COLUMN4, COLUMN5)
) unpvt
) AS t LEFT OUTER JOIN
COLUMN_DEF c ON t.COLUMN_NAME = c.MAPPED_COLUMN
) b
PIVOT
(
MAX(COLUMN_VALUES) FOR MAPPED_COLUMN_VAL IN ( ' + #new_names + ' )
--IN ([FIRST NAME], [LAST NAME])
) AS pivot_table;'
EXEC dbo.SP_EXECUTESQL #sql
Unpivot Will remove columns with NULL values.
INPUT:
ID COLUMN1 COLUMN2 COLUMN3 COLUMN4 COLUMN5 DEF_ID
1 JOHN DOE NULL NULL NULL 1
2 TOM BAKER NULL NULL NULL 2
DEF_ID MAPPED_COLUMN MAPPED_COLUMN_VAL
1 COLUMN1 FIRST NAME
2 COLUMN2 LAST NAME
RESULT:
ID DEF_ID FIRST NAME LAST NAME
1 1 JOHN DOE
2 2 TOM BAKER

In general I think that this requires pl/sql and dynamic SQL as stated by #gordon-linoff
This is gets very close.
Create table temp_sgc1(id number, column1 Varchar2(20), column2 varchar2(20));
Insert into temp_sgc1 values(1 , 'John' , 'Doe');
Insert into temp_sgc1 values(2 , 'Tom' , 'Baker');
Create table temp_sgc2(def_id number, mapped_column Varchar2(20), mapped_column_va
l
varchar2(20));
Insert into temp_sgc2 values(1, 'column1', 'First Name');
Insert into temp_sgc2 values(1, 'column2', 'Last Name');
Select * from
(select * from temp_sgc2
pivot (
max(mapped_column_val) for mapped_column in ( 'column1' column1, 'column2' column2 )
)
order by def_id)
union all
Select id, column1, column2
from temp_sgc1
;
RESULT:
DEF_ID COLUMN1 COLUMN2
1 First Name Last Name
1 John Doe
2 Tom Baker

Related

Concatenate or merge many columns values with a separator between and ignoring nulls - SQL Server 2016 or older

I want to simulate the CONCAT_WS SQL Server 2017+ function with SQL Server 2016 version or older in order to concatenate many columns which values are strings like that:
Input:
| COLUMN1 | COLUMN2 | COLUMN3 | COLUMN4 |
'A' 'B' NULL 'D'
NULL 'E' 'F' 'G'
NULL NULL NULL NULL
Output:
| MERGE |
'A|B|D'
'E|F|G'
NULL
Notice that the output result is a new column that concatenate all values separated by '|'. The default value should be NULL if there are no values in the columns.
I tried with CONCAT and a CASE statement with many WHEN conditions but is really dirty and I am not allowed to use this solution. Thanks in advance.
One convenient way is:
select stuff( coalesce(',' + column1, '') +
coalesce(',' + column2, '') +
coalesce(',' + column3, '') +
coalesce(',' + column4, ''), 1, 1, ''
)
Here is another method by using XML and XQuery.
The number of columns is not hard-coded, it could be dynamic.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (id INT IDENTITY PRIMARY KEY, col1 CHAR(1), col2 CHAR(1), col3 CHAR(1), col4 CHAR(1));
INSERT INTO #tbl (col1, col2, col3, col4) VALUES
( 'A', 'B', NULL, 'D'),
(NULL, 'E' , 'F' , 'G'),
(NULL, NULL, NULL , NULL);
-- DDL and sample data population, end
DECLARE #separator CHAR(1) = '|';
SELECT id, REPLACE((
SELECT *
FROM #tbl AS c
WHERE c.id = p.id
FOR XML PATH('r'), TYPE, ROOT('root')
).query('data(/root/r/*[local-name() ne "id"])').value('.', 'VARCHAR(100)') , SPACE(1), #separator) AS concatColumns
FROM #tbl AS p;
Output
+----+---------------+
| id | concatColumns |
+----+---------------+
| 1 | A|B|D |
| 2 | E|F|G |
| 3 | |
+----+---------------+

Show 2 columns in 2 different rows - SQL

I need to separate two columns into two rows in sql
I have this:
Column1 Column2 Column3
Car 2 5
Boat 4
Truck 6
And I want this:
Column1 Column2
Car 2
Car 5
Boat 4
Truck 6
How can I do this in SQL?
This operation is unpivoting. I would recommend apply:
select t.column1, v.col
from t cross apply
(values (col1), (col2)) v(col)
where v.col is not null;
This should do it
select Column1, Column2
from tbl where Column2 is not null and Column2 <> ''
union
select Column1, Column3
from tbl where Column3 is not null and Column3 <> ''

MS SQL Server select rows with max values

Good day
I have Table1:
COLUMN1 COLUMN2 Column3
----------------------------
Eva Apple 1
Eva Apple 2
Eva Apple 3
Eva Apple 4
Eva Apple 5
Eva Apple 6
Bob Apple 1
Bob Samsung 1
Bob Samsung 2
... ... ...
I need
COLUMN1 COLUMN2 Column3
----------------------------
Eva Apple 6
Bob Samsung 2
Bob Apple 1
... ... ...
How i can setup string for select only rows with MAX values in Column3 ?
My version of string is :
SELECT MAX(Column3) , [column2], [Column2]
FROM Table1
WHERE Column3 = MAX ;
Thanks for Opinions
You can use row_number
Select top (1) with ties *
from table1
order by row_number() over (partition by Column1, Column2 order by Column3 desc)
Other way is to use outer query:
Select * from (
Select *, RowN = row_number() over (partition by Column1, Column2 order by Column3 desc) from table1 ) a
Where a.RowN = 1
You want to find the maximum Column3 for each combination of Column1 and Column2.
You can achieve this with a GROUP BY
SELECT Column1, Column2, MAX(Column3)
FROM Table1
GROUP BY Column1, Column2
See https://learn.microsoft.com/en-us/sql/t-sql/queries/select-group-by-transact-sql
select * from (
SELECT *, rn=ROW_NUMBER() over (partition by COLUMN1,COLUMN2,Column3 order by
Column3 desc)
FROM Table1
)
WHERE rn=1
Please try the following:
WITH B AS
(
SELECT
Column1, Column2, Column3,
ROW_NUMBER() OVER (PARTITION BY Column1, Column2 ORDER BY Column3 DESC) AS row_num
FROM
Table1
)
SELECT Column1, Column2, Column3
FROM B
WHERE row_num = 1
You need to add a group by. In queries of this type, you have a set of columns you want the values from (these are the columns you group by) and you have other columns most of whose values you'll throw away. You use a function like MAX, MIN, SUM, AVG to specify what to do with the data from rows that are "thrown away". The result is a unique set of values from the columns that were grouped, and a single value corresponding to the min/max/avg etc from the columns that were not grouped:
SELECT [column1], [Column2], MAX(Column3) as Column3
FROM Table1
GROUP BY Column3 ;
Add a Group by on column 3.
Select col1, col2, max(col3)
from test
Group By col3
You can use a function like DENSE_RANK().
In this example, if there are duplicate values you want to retrieve.
declare #t as table (COLUMN1 char(3), COLUMN2 varchar(10), COLUMN3 int)
INSERT #t (COLUMN1 , COLUMN2 , COLUMN3 ) select 'Eva', 'Apple' ,1
INSERT #t (COLUMN1 , COLUMN2 , COLUMN3 ) select 'Eva', 'Apple' ,2
INSERT #t (COLUMN1 , COLUMN2 , COLUMN3 ) select 'Eva', 'Apple' ,3
INSERT #t (COLUMN1 , COLUMN2 , COLUMN3 ) select 'Bob', 'Apple' ,1
INSERT #t (COLUMN1 , COLUMN2 , COLUMN3 ) select 'Bob', 'Samsung' ,1
INSERT #t (COLUMN1 , COLUMN2 , COLUMN3 ) select 'Bob', 'Samsung' ,2
SELECT * FROM (
SELECT DENSE_RANK() OVER (PARTITION BY COLUMN1, COLUMN2 ORDER BY COLUMN1, COLUMN3 desc) [Max] , * from #t ) as T
WHERE max = 1 -- Set here what position do you want
Order by COLUMN3

Take values of different columns in the same 1 column table

I am working on Ms Sql Server 2008 R2.
now i want one column which has results of 3 different columns of same table..
Let me explain with Figure.
Table: mainTable
Id Column1 Column2 Column3
-------------------------------------
1 urla urlb urlc
2 urld urle urlf
3 urlg urlh urli
Now i want one column
Table Name: ResultTable
Id ColumnResult
-------------
1 urla
2 urlb
3 urlc
4 urld
5 urle
6 urlf
7 urlg
8 urlh
9 urli
Thanks in Advance.
Sahil Patel
You can use UNION ALL:
SELECT
Id = ROW_NUMBER() OVER(ORDER BY ColumnResult),
Column1
FROM (
SELECT Id, Column1 AS ColumnResult FROM mainTable UNION ALL
SELECT Id, Column2 FROM mainTable UNION ALL
SELECT Id, Column3 FROM mainTable
)t

Query to get only the duplicate data

I have a table with data
ID Name
1 John
2 Robert
3 John
4 Sam
5 Jack
6 Sam
Now i want ony the the duplicate names ony through query
ie..,
Name
John
Sam
SELECT Name
FROM YourTable
GROUP BY Name
HAVING COUNT(*) > 1
CREATE TABLE MyTable (
ID int
, Name nvarchar(50)
)
INSERT MyTable VALUES ( 1, 'John' )
INSERT MyTable VALUES ( 2, 'Robert' )
INSERT MyTable VALUES ( 3, 'John' )
INSERT MyTable VALUES ( 4, 'Sam' )
INSERT MyTable VALUES ( 5, 'Jack' )
INSERT MyTable VALUES ( 6, 'Sam' )
SELECT
Name
FROM
MyTable
GROUP BY
Name
HAVING
COUNT(*) > 1
DROP TABLE MyTable
Results:
Name
--------------------------------------------------
John
Sam
with temp as (
select Name, count(Name) as countOfNames
from myTable
group by Name
)
select Name from temp
where countOfNames > 1
select columnname,count(column name) from tablename group by column name having count(*)>1