Simple SQL Pivot returning null - sql

I am having one of those days.
I am trying to pivot the data below into columns
ID | SplitString
-------------------
| 1 | ABC
| 2 | ABC03082017
| 3 | 03082017
| 4 | 1
| 5 | TestData
So far I have the code below but when I run it, it is returning nulls, the columns have the correct header but the data is all null.
select *
from
(
select ID,splitData from dbo.fn_splitstring(#RawData_Header, '|')
) src
pivot
(
MAX(ID) for splitData in ([Identifier], [ProviderCode], [FileDate],[Code],[FileName])
) piv;
The first part of the pivot script is working correctly and returning the table above.
EDIT**
I am trying to return the data similar to the image below
Thanks for your help
Noelle

If you want to use PIVOT, you have to change your code to:
select [1] AS [Identifier], [2] AS [ProviderCode], [3] AS [FileDate], [4] AS [Code], [5] AS [FileName]
from
(
select ID,splitData from dbo.fn_splitstring(#RawData_Header, '|')
) src
pivot
(
MAX(splitData) for Id in ([1],[2],[3],[4],[5])
) piv;
Read more about PIVOT and UNPIVOT.

Related

Extract the maximum value from the last number in a hierarchyID?

I have a column with hierarchy IDs converted to strings in SQL Server. I need to add new hierarcyIDs for the new lines, but first I have to find the last child of the current ID. The hierarchyIDs are look like these:
/1/1/1/6/1/
/1/1/1/6/7/
/1/1/1/6/3/
/1/1/1/6/13/
/1/1/1/6/4/
As you can see, the maximum number is not equal with the count of the lines, so I can not use count()+1 unfortunately.
What I need to extract from this list is:
13
I only have experience in PL SQL, where it was easy to do this with regexp functions, but I can not find the solution in SQL Server.
You can use some STRING operation as below to get your desired output-
DEMO HERE
WITH your_table(your_column)
AS
(
SELECT '/1/1/1/6/1/' UNION ALL
SELECT '/1/1/1/6/7/' UNION ALL
SELECT '/1/1/1/6/3/' UNION ALL
SELECT '/1/1/1/6/13/' UNION ALL
SELECT '/1/1/1/6/4/'
)
SELECT
MAX(
CAST(
REVERSE(
LEFT(
REVERSE(LEFT(your_column,LEN(your_column)-1)),
CHARINDEX('/',REVERSE(LEFT(your_column,LEN(your_column)-1)) ,0) - 1
)
)
AS INT
)
)
FROM your_table
Note: Data has to be as your sample data
The creators of hierarchyid have anticipated your needs and have an officially supported solution for this.
declare #h table (h HIERARCHYID);
insert into #h (h)
values
('/1/1/1/6/1/'),
('/1/1/1/6/7/'),
('/1/1/1/6/3/'),
('/1/1/1/6/13/'),
('/1/1/1/6/4/');
declare #parent HIERARCHYID = '/1/1/1/6/';
declare #maxChild HIERARCHYID = (
select max(h)
from #h
where h.IsDescendantOf(#parent) = 1
);
-- ToString() added here for readability in the output;
-- it's not needed to be used as data.
select #parent.GetDescendant(#maxChild, null).ToString();
You can read more about this here.
Another way around this is to specify your own components to the hierarchyid yourself. I like to use the primary key values. For example, let's say that this data represents a company's org chart. If EmployeeID 1 is the CEO, 42 is the CFO (who reports to the CEO) and 306 is Accounting Manager (who reports to the CFO), the latter's hierarchyid would be /1/42/306/. Because the PK values are unique, the generated hierarchid is also unique.
To give some ideas, 2 solutions.
The first one is for Sql Server 2017 and beyond.
The second for most versions below that.
create table YourTable
(
ID int identity(101,1) primary key,
hierarcyIDs varchar(100)
)
GO
✓
insert into YourTable
(hierarcyIDs) values
('/1/2/3/4/5/')
,('/1/2/3/4/15/')
,('/1/2/3/4/10/')
,('/11/12/13/14/15/')
,('/11/12/13/14/42/')
;
GO
5 rows affected
SELECT
[1] as id1,
[2] as id2,
[3] as id3,
[4] as id4,
max([5]) as id5,
concat_ws('/','',[1],[2],[3],[4],max([5])+1,'') as nextHierarcyIDs
FROM YourTable
OUTER APPLY
(
select *
from
( select try_cast(value as int) as id
, row_number() over (order by (select 0)) rn
from string_split(trim('/' from hierarcyIDs),'/') s
) src
pivot (max(id)
for rn in ([1],[2],[3],[4],[5])
) pvt
) anarchy
group by [1],[2],[3],[4]
GO
id1 | id2 | id3 | id4 | id5 | nextHierarcyIDs
--: | --: | --: | --: | --: | :---------------
1 | 2 | 3 | 4 | 15 | /1/2/3/4/16/
11 | 12 | 13 | 14 | 42 | /11/12/13/14/43/
SELECT hierarcyIdLvl1to4
, MAX(hierarcyIDLvl5) AS maxHierarcyIDLvl5
FROM
(
SELECT id, hierarcyIDs
, substring(hierarcyIDs, 0, len(hierarcyIDs)-charindex('/',
reverse(hierarcyIDs),2)+2) AS hierarcyIdLvl1to4
, reverse(substring(reverse(hierarcyIDs),2,charindex('/',
reverse(hierarcyIDs),2)-2)) AS hierarcyIDLvl5
FROM YourTable
) q
GROUP BY hierarcyIdLvl1to4
GO
hierarcyIdLvl1to4 | maxHierarcyIDLvl5
:---------------- | :----------------
/1/2/3/4/ | 5
/11/12/13/14/ | 42
db<>fiddle here

Oracle Pivot Based on Multiple Columns

I am fairly new to Pivoting and trying to Pivot based on two columns.
Data I have:
Data I want to Achieve after pivoting:
My Query which is Flawed:
select *
from
(
select ISSUEID,ANSWER, ANSWERCOMMENT,QUESTION ,QUESTIONID
from issue_survey
WHERE ISSUEID = 6877
) d
pivot
(
max(QUESTION)
for QUESTIONID in (1 QUESTION1,2 QUESTION2, 3 QUESTION3)
) piv;
The Results I am getting with this flawed query:
Any suggestions with this are appreciated. Thank you!
Try:
select *
from
(
select ISSUEID,ANSWER, ANSWERCOMMENT,QUESTION ,
rownum rn
from issue_survey
WHERE ISSUEID = 6877
) d
pivot
(
max(QUESTION) as question, max(Answer) as answer,
max( ANSWERCOMMENT ) as ANSWERCOMMENT
for rn in ( 1 ,2 , 3 )
) piv;
Demo: http://www.sqlfiddle.com/#!4/e5aba7/6
| ISSUEID | 1_QUESTION | 1_ANSWER | 1_ANSWERCOMMENT | 2_QUESTION | 2_ANSWER | 2_ANSWERCOMMENT | 3_QUESTION | 3_ANSWER | 3_ANSWERCOMMENT |
|---------|-------------------|----------|-----------------|--------------|----------|-----------------|-----------------|----------|-----------------|
| 6877 | Do you wanna wait | YES | TEST1 | How about it | Its okay | TEST2 | Sample question | (null) | TEST3

Combine two rows in single column with same Id

This is currently how I return values. but I want to combine rows that have the same Id's. I tried using the unpivot but I couldn't get it to work.
here's my query:
SELECT * FROM
(
SELECT
ID,
Setup,
Message
FROM myViewHere
)
AS tempTable
UNPIVOT
(
[Message]
FOR Test
IN (ID, Setup)
) AS PVT
This is the result of myViewHere
|ID | Setup | Message |
|---|--------|----------|
| 1 | Header | myHeader |
|---|--------|----------|
| 1 | Footer | myFooter |
What I want to achieve:
|ID | Header | Footer |
|---|----------|----------|
| 1 | myHeader | myFooter |
|---|----------|----------|
Typical pivot case https://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx
Assumed table name is "source"
SELECT ID, [Header], [Footer]
FROM source
PIVOT
( max(Message) FOR Setup IN ([Header], [Footer])) p;
See test on sqlfeedle http://sqlfiddle.com/#!6/7635f/7
you can change your view query to be like below
SELECT * FROM
(
SELECT
ID,
Setup,
Message
FROM myViewHere
)
AS tempTable
UNPIVOT
(
[Message]
FOR Test
IN (ID, Setup)
) AS UNPVT
PIVOT
(
MAX([Message])
FOR [Setup]
IN ([Header], [Footer])
)PVT

How do I Pivot Vertical Data to Horizontal Data SQL with Variable Row Lengths?

Okay I have the following table.
Name ID Website
Aaron | 2305 | CoolSave1
Aaron | 8464 | DiscoWorld1
Adriana | 2956 | NewCin1
Adriana | 5991 | NewCin2
Adriana | 4563 NewCin3
I would like to transform it into the following way.
Adriana | 2956 | NewCin1 | 5991 | NewCin2 | 4563 | NewCin3
Aaron | 2305 | CoolSave1 | 8464 | DiscoWorld | NULL | NULL
As you can see i am trying to take the first name from the first table and make a single row with all the IDs / Websites associated with that name. The problem is, there is a variable amount of websites that may be associated with each name. To handle this i'd like to just make a table with with the number of fields sequal to the max line item, and then for the subsequent lineitems, plug in a NULL where there are not enough data.
In order to get the result, you will need to apply both the UNPIVOT and the PIVOT functions to the data. The UNPIVOT will take the columns (ID, website) and convert them to rows, once this is done, then you can PIVOT the data back into columns.
The UNPIVOT code will be similar to the following:
select name,
col+'_'+cast(col_num as varchar(10)) col,
value
from
(
select name,
cast(id as varchar(11)) id,
website,
row_number() over(partition by name order by id) col_num
from yt
) src
unpivot
(
value
for col in (id, website)
) unpiv;
See SQL Fiddle with Demo. This gives a result:
| NAME | COL | VALUE |
-------------------------------------
| Aaron | id_1 | 2305 |
| Aaron | website_1 | CoolSave1 |
| Aaron | id_2 | 8464 |
| Aaron | website_2 | DiscoWorld1 |
As you can see I applied a row_number() to the data prior to the unpivot, the row number is used to generate the new column names. The columns in the UNPIVOT must also be of the same datatype, I applied a cast to the id column in the subquery to convert the data to a varchar prior to the pivot.
The col values are then used in the PIVOT. Once the data has been unpivoted, you apply the PIVOT function:
select *
from
(
select name,
col+'_'+cast(col_num as varchar(10)) col,
value
from
(
select name,
cast(id as varchar(11)) id,
website,
row_number() over(partition by name order by id) col_num
from yt
) src
unpivot
(
value
for col in (id, website)
) unpiv
) d
pivot
(
max(value)
for col in (id_1, website_1, id_2, website_2, id_3, website_3)
) piv;
See SQL Fiddle with Demo.
The above version works great if you have a limited or known number of values. But if the number of rows is unknown, then you will need to use dynamic SQL to generate the result:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME( col+'_'+cast(col_num as varchar(10)))
from
(
select row_number() over(partition by name order by id) col_num
from yt
) t
cross apply
(
select 'id' col union all
select 'website'
) c
group by col, col_num
order by col_num, col
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT name,' + #cols + '
from
(
select name,
col+''_''+cast(col_num as varchar(10)) col,
value
from
(
select name,
cast(id as varchar(11)) id,
website,
row_number() over(partition by name order by id) col_num
from yt
) src
unpivot
(
value
for col in (id, website)
) unpiv
) x
pivot
(
max(value)
for col in (' + #cols + ')
) p '
execute(#query);
See SQL Fiddle with Demo. Both versions give the result:
| NAME | ID_1 | WEBSITE_1 | ID_2 | WEBSITE_2 | ID_3 | WEBSITE_3 |
------------------------------------------------------------------------
| Aaron | 2305 | CoolSave1 | 8464 | DiscoWorld1 | (null) | (null) |
| Adriana | 2956 | NewCin1 | 4563 | NewCin3 | 5991 | NewCin2 |

How to Split Data in TSQL

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).