I have table like this
id | vname1 | vname2 | vname3
1 | vala | valb | valc
I want this to convert like this
id | vname | vals
1 | vname1 | vala
1 | vname2 | valb
1 | vname3 | valc
I thought about pivoting but here I think is not the case
Do a UNION ALL, with one SELECT for each vname column:
select id, 'vname1' as vname, vname1 as vals from tablename
union all
select id, 'vname2' as vname, vname2 as vals from tablename
union all
select id, 'vname3' as vname, vname3 as vals from tablename
You can use the UNPIVOT function to convert the columns into rows:
Sample Example:
select Id,
indicatorname,
from yourtable
unpivot
(
indicatorvalue
for indicatorname in (Indicator1, Indicator2, Indicator3)
) unpiv;
Link for reference: UnPivot
Related
I have a table table1 like below
+----+------+------+------+------+------+
| id | loc | val1 | val2 | val3 | val4 |
+----+------+------+------+------+------+
| 1 | loc1 | 10 | 190 | null | 20 |
| 2 | loc2 | 20 | null | 10 | 10 |
+----+------+------+------+------+------+
need to combine the val1 to val4 into a new column val with a row for each so that the output is like below.
NOTE: - I data I have has val1 to val30 -> ie. 30 columns per row that need to be converted into rows.
+----+------+--------+
| id | loc | val |
+----+------+--------+
| 1 | loc1 | 10 |
| 1 | loc1 | 190 |
| 1 | loc1 | null |
| 1 | loc1 | 20 |
| 2 | loc2 | 20 |
| 2 | loc2 | null |
| 2 | loc2 | 10 |
| 2 | loc2 | 10 |
+----+------+--------+
You can use lateral join for transform columns to rows :
SELECT a.id,a.loc,t.vals
FROM table1 a,
unnest(ARRAY[a.val1,a.val2,a.val3,a.val4]) t(vals);
If you want to this with a dynamic added columns:
CREATE OR REPLACE FUNCTION columns_to_rows(
out id integer,
out loc text,
out vals integer
)
RETURNS SETOF record AS
$body$
DECLARE
columns_to_rows text;
BEGIN
SELECT string_agg('a.'||attname, ',') into columns_to_rows
FROM pg_attribute
WHERE attrelid = 'your_table'::regclass AND --table name
attnum > 0 and --get just the visible columns
attname <> all (array [ 'id', 'loc' ]) AND --exclude some columns
NOT attisdropped ; --column is not dropped
RETURN QUERY
EXECUTE format('SELECT a.id,a.loc,t.vals
FROM your_table a,
unnest(ARRAY[%s]) t(vals)',columns_to_rows);
end;
$body$
LANGUAGE 'plpgsql'
Look at this link for more detail: Columns to rows
You could use a cross join with generate_series for this:
select
id,
loc,
case x.i
when 1 then val1
when 2 then val2
. . .
end as val
from t
cross join generate_series(1, 4) x (i)
It uses the table only once and can be easily extended to accommodate more columns.
Demo
Note: In the accepted answer, first approach reads the table many times (as many times as column to be unpivoted) and second approach is wrong as there is no UNPIVOT in postgresql.
I'm sure there's a classier approach than this.
SELECT * FROM (
select id, loc, val1 as val from #t a
UNION ALL
select id, loc, val2 as val from #t a
UNION ALL
select id, loc, val3 as val from #t a
UNION ALL
select id, loc, val4 as val from #t a
) x
order by ID
Here's my attempt with unpivot but cant get the nulls, perhaps perform a join for the nulls? Anyway i'll still try
SELECT *
FROM (
SELECT * FROM #t
) main
UNPIVOT (
new_val
FOR val IN (val1, val2, val3, val4)
) unpiv
It will not work in postgress as needed by user. Saw when it was mentioned in comments.
I am finding a way to handle "NULL"
select p.id,p.loc,CASE WHEN p.val=0 THEN NULL ELSE p.val END AS val
from
(
SELECT id,loc,ISNULL(val1,0) AS val1,ISNULL(val2,0) AS val2,ISNULL(val3,0) AS val3,ISNULL(val4,0) AS val4
FROM Table1
)T
unpivot
(
val
for locval in(val1,val2,val3,val4)
)p
Test
EDIT:
Best Solution from my Side:
select a.id,a.loc,ex.val
from (select 'val1' as [over] union all select 'val2' union all select 'val3'
union all select 'val1' ) pmu
cross join (select id,loc from Table1) as a
left join
Table1 pt
unpivot
(
[val]
for [over] in (val1, val2, val3, val4)
) ex
on pmu.[over] = ex.[over] and
a.id = ex.id
Test
I am creating complicated CTE Query. In MSSQL
Which result will be something like that
| Id1 | Id2 | Id3 |
| 1 | 2 | 3 |
| 5 | 4 | 1 |
| 6 | 5 | 2 |
And now I need to combine all data into on column something like that
| Ids |
| 1 |
| 2 |
| 3 |
| 5 |
| 4 |
| 1 |
| 6 |
| 5 |
| 2 |
I want to try avoid union all and select by each column
Thanks
My favorite way of doing this uses cross apply:
select v.id
from t cross apply
(values (t.id1), (t.id2), (t.id3)) v(id);
Like the version using unpivot this only reads the table once. A version using union all would scan the table three times. However, cross apply is much more powerful than unpivot and requires less typing.
AFAIK, there is no different options other than usuing UNION operation. Basic purpose of UNION operation is that only ... combining records from multiple sources/result sets. So you can do like
select Id1 from tbl1
union
select Id3 from tbl1
union
select Id2 from tbl1
You could use UNPIVOT
SELECT Ids
FROM
(
SELECT Id1, Id2, Id3
FROM CTE
) d
UNPIVOT
(
Ids for id in (Id1, Id2, Id3)
) u
Use UNPIVOT table to get your result :
CREATE TABLE #table( Id1 INT ,Id2 INT , Id3 INT )
INSERT INTO #table( Id1 ,Id2 , Id3 )
SELECT 1 , 2 , 3 UNION ALL
SELECT 5 , 4 , 1 UNION ALL
SELECT 6 , 5 , 2
SELECT _Result [Result]
FROM
(
SELECT Id1 ,Id2 , Id3
FROM #table
)A
UNPIVOT
(
_Result FOR Id IN (Id1 , Id2 , Id3)
) UNPvt
I have SQL table what looks like:
+----------+-----------+
| ID | Direction |
+----------+-----------+
| 1 | left |
| 1 | null |
| 2 | left |
| 2 | null |
| 3 | null |
| 4 | left |
| 4 | null |
| 5 | null |
+----------+-----------+
I want to show each value only once:
If there will be ID 1 with Direction null and left, then show only ID 1 with direction left.
If there will be ID 1 only with null value, show it with null value.
Use a common table expression (cte):
with cte as
(
Your huge select...
)
select *
from cte t1
where t1.Direction = 'left'
or not exists (select * from cte t2
where t2.kanbanid = t1.kanbanid
and t2.Direction = 'left')
I.e. if your select has Direction 'left' for a kanbanid, return that row. Also return that row if same kanbanid has no Direction 'left' at all.
Why wont below query work:
select id,max(dir)
from #temp
group by id
below is test data:
create table #temp
(
id int,
dir char(10)
)
insert into #temp
select 1,'left'
union all
select 1,null
union all
select 2,null
union all
select 3,'right'
union all
select 3,null
union all
select 3,null
select id,max(dir)
from #temp
group by id
aggregate functions will ignore null,below is the output:
select distinct *,
row_number() over (partition by id order by ,Direction )as row1 into #any_table
from #your_table_name
select * from #any_table
where row1 =1
Before I begin, I know there is a whole bunch of questions on Stackoverflow on this topic but I could not find any of them relevant to my case because they involve something much more complicated than what I need.
What I want is a simple dumb transpose with no logic involved.
Here is the original table that my select query returns:
Name Age Sex DOB Col1 Col2 Col3 ....
A 12 M 8/7 aa bb cc
Typically, this is going to contain only 1 record i.e. for one person
Now what I want is
Field Value
Name A
Age 12
Sex M
DOB 8/7
Col1 aa
Col2 bb
Col3 cc
.
.
So there is no counting, summing or any complicated logic involved like most of the similar question on Stackoverflow.
How do I do it?
I read through the PIVOT and UNPIVOT help and it was not that helpful at all.
PS: By chance, if it contains more than one records, is it possible to return each record as a field somewhat like
Field Value1 Value2 Value3 ...
Name A B C ...
Age .. .. .. ...
.
.
I want to know how to to do this for Oracle 10g and 11g
PS:Feel free to tag as duplicate if you find a question that is truly similar to mine.
I would suggest applying the UNPIVOT function first to your multiple columns, then using row_number() to create your new column names that will be used in the PIVOT.
The basic syntax for the unpivot will be
select field,
value,
'value'||
to_char(row_number() over(partition by field
order by value)) seq
from yourtable
unpivot
(
value
for field in (Name, Age, Sex, DOB, col1, col2, col3)
) u;
See SQL Fiddle with Demo. This is going to convert your multiple columns of data into multiple rows. I used row_number() to create a unique value for your new column names, the data from this query looks like:
| FIELD | VALUE | SEQ |
|-------|-------------------------|--------|
| AGE | 12 | value1 |
| AGE | 15 | value2 |
| COL1 | aa | value1 |
| COL1 | xx | value2 |
Then you can apply the PIVOT function to this result:
select field, value1, value2
from
(
select field,
value,
'value'||
to_char(row_number() over(partition by field
order by value)) seq
from yourtable
unpivot
(
value
for field in (Name, Age, Sex, DOB, col1, col2, col3)
) u
) d
pivot
(
max(value)
for seq in ('value1' as value1, 'value2' as value2)
) piv
See SQL Fiddle with Demo. This gives a final result:
| FIELD | VALUE1 | VALUE2 |
|-------|-------------------------|-------------------------|
| AGE | 12 | 15 |
| COL1 | aa | xx |
| COL2 | bb | yy |
| COL3 | cc | zz |
| DOB | 07-Aug-2001 12:00:00 AM | 26-Aug-2001 12:00:00 AM |
| NAME | A | B |
| SEX | F | M |
Note, when you are applying the unpivot function the datatype of all of the columns must be the same so you might have to convert your data in a subquery before you can unpivot it.
The UNPIVOT/PIVOT function were introduced in Oracle 11g, if you are using Oracle 10g, then you can edit the query to use:
with cte as
(
select 'name' field, name value
from yourtable
union all
select 'Age' field, Age value
from yourtable
union all
select 'Sex' field, Sex value
from yourtable
union all
select 'DOB' field, DOB value
from yourtable
union all
select 'col1' field, col1 value
from yourtable
union all
select 'col2' field, col2 value
from yourtable
union all
select 'col3' field, col3 value
from yourtable
)
select
field,
max(case when seq = 'value1' then value end) value1,
max(case when seq = 'value2' then value end) value2
from
(
select field, value,
'value'||
to_char(row_number() over(partition by field
order by value)) seq
from cte
) d
group by field;
See SQL Fiddle with Demo
need some help figuring out how to split up some data
the Data Currently looks like this
╔═════════════════════════════════════════════╗
║ Name Data1 Data2 Data3 Field1 field2 Field3 ║
╠═════════════════════════════════════════════╣
║ a 1 2 3 x y z ║
╚═════════════════════════════════════════════╝
I need to split that data so that it looks like this
+-----------------+
| name data field |
+-----------------+
| a 1 x |
| a 2 y |
| a 3 z |
+-----------------+
can anyone help me with this
Depending on your version of SQL Server. Starting in SQL Server 2008, you can unpivot the data using CROSS APPLY:
SELECT t.name,
x.Data,
x.Field
FROM YourTable t
CROSS APPLY
(
VALUES
(t.Data1, t.Field1),
(t.Data2, t.Field2),
(t.Data3, t.Field3)
) x (Data, Field);
See SQL Fiddle with Demo.
This can also be done using the UNPIVOT and the PIVOT function in SQL Server 2005+:
select name, data, field
from
(
select name, left(col, len(col) -1) col, value,
row_number() over(partition by left(col, len(col) -1) order by col) rn
from
(
select name,
cast([Data1] as varchar(10)) Data1,
cast([Data2] as varchar(10)) Data2,
cast([Data3] as varchar(10)) Data3,
[Field1], [field2], [Field3]
from yourtable
) src
unpivot
(
value
for col in ([Data1], [Data2], [Data3],
[Field1], [field2], [Field3])
) unpiv
) u
pivot
(
max(value)
for col in (data,field)
) piv
See SQL Fiddle with Demo
Both give the result:
| NAME | DATA | FIELD |
-----------------------
| a | 1 | x |
| a | 2 | y |
| a | 3 | z |
There are many ways to do this (just look at bluefeet's answer), but a simple way can be using UNION ALL :
SELECT [Name], Data1 AS Data, Field1 AS Field
FROM YourTable
UNION ALL
SELECT [Name], Data2 AS Data, Field2 AS Field
FROM YourTable
UNION ALL
SELECT [Name], Data3 AS Data, Field3 AS Field
FROM YourTable
And here is a fiddle with a demo for this (courtesy of bluefeet).