I need to unpivot columns to rows where pairs of columns stay together in the results - sql

The following article comes close, but I can't make the leap to my need: Unpivot pairs of associated columns to rows
IF OBJECT_ID ('dbo.tst_CrossApply') IS NOT NULL
DROP TABLE dbo.tst_CrossApply;
create table dbo.tst_CrossApply
(
GivenDay varchar(32) null,
OtherData varchar(32) null,
CODRPL varchar(32) null,
COD varchar (32) null,
BODRPL varchar(32) null,
BOD varchar (32) null,
)
go
insert into dbo.tst_CrossApply values ( 'Day1','OtherData1','<', '5','', '10')
insert into dbo.tst_CrossApply values ( 'Day2','OtherData2', '', '20','<', '30')
go
SELECT * FROM dbo.tst_CrossApply
SELECT t.[GivenDay],t.[OtherData],v.[RPL],v.[Result]
FROM [dbo].[tst_CrossApply] t
CROSS APPLY (VALUES ([CODRPL], [COD]),([BODRPL], [BOD])) v ([RPL],[Result])
The above script returns the above with the second piture minus the needed Column 'Parameter'.
I can get this column, but not the pairing of the RPL and Result columns using UNPIVOT
In my database there are several 'OtherData' columns, and several pairs of columns to CrossApply and/or UNPIVOT.
The following includes the Parameter column I need, which is one of the second of the paried column headings.
Any help is appreciated.

You're close. See the "Unpivoting" example linked in the next thread.
SELECT t.[GivenDay]
, t.[OtherData]
, v.[Param]
, v.[RPL]
, v.[Result]
FROM [dbo].[tst_CrossApply] t
CROSS APPLY (
VALUES ('COD', [CODRPL], [COD])
, ('BOD', [BODRPL], [BOD])
) v ([Param], [RPL],[Result])
Update 2022-03-02
I'm not aware of a simple alternative using UNPIVOT. The closest I could get was more convoluted than just using CROSS APPLY
SELECT cod.GivenDay, cod.OtherData, cod.Param, cod.RPL, cod.Result
FROM (
SELECT GivenDay, OtherData, COD, CODRPL AS RPL
FROM [dbo].[tst_CrossApply] t
) pvt
UNPIVOT
(
Result FOR Param IN (COD)
) AS cod
UNION ALL
SELECT bod.GivenDay, bod.OtherData, bod.Param, bod.RPL, bod.Result
FROM (
SELECT GivenDay, OtherData, BOD, BODRPL AS RPL
FROM [dbo].[tst_CrossApply] t
) pvt
UNPIVOT
(
Result FOR Param IN (BOD)
) AS bod
ORDER BY GivenDay, OtherData, Param
db<>fiddle here

Related

is possible to unpivot a sql server table using headers as a column and values as another column?

I have a table like this:
TableName
dates
ModelName
BaseUnitPerPallet
pallet
Calendar
June
Null
4
1
Country
June
Null
2
6
Product
June
DOWNSTREAM
Null
8
ProductBOM
June
DOWNSTREAM
9
9
and I want a table like this:
Columns
values
TableName
Calendar
TableName
Country
TableName
Product
TableName
ProductBOM
where columns field is the headers of the previous table, and values are the values in an unpivot way.
I have been trying without success the unpivot logic:
SELECT Columns, Values
FROM
(
SELECT TableName, dates, ModelName, BaseUnitPerPallet, pallet
FROM Database
as source_query
)
UNPIVOT
(
Values FOR Columns IN ( TableName, dates, ModelName, BaseUnitPerPallet, pallete)
)
as pivot_results
any advice or guidance would be great.
Additionally, any resource to do this dinamic? and apply the logic without write the column names?
Thanks in advanceĀ”
I'd recommend using APPLY to unpivot your table
Unpivot using APPLY
DROP TABLE IF EXISTS #YourTable
CREATE TABLE #YourTable (
ID INT IDENTITY(1,1) PRIMARY KEY
,TableName VARCHAR(100)
,Dates Varchar(25)
,ModelName VARCHAR(100)
,BaseUnitPerPallet TINYINT
,Pallet TINYINT
)
INSERT INTO #YourTable
VALUES
('Calendar','June',NULL,4,1)
,('Country','June',NULL,2,6)
,('Product','June','DOWNSTREAM',NULL,8)
,('ProductBOM','June','DOWNSTREAM',9,9)
SELECT A.ID,B.*
FROM #YourTable AS A
CROSS APPLY
(VALUES
('TableName',A.TableName)
,('Dates',A.Dates)
,('ModelName',A.ModelName)
,('BaseUnitPerPallet',CAST(A.BaseUnitPerPallet AS Varchar(100)))
,('Pallet',CAST(A.Pallet AS Varchar(100)))
) AS B(ColumnName,Val)
--WHERE B.Val IS NOT NULL /*Optional in case you want to ignore NULLs*/
ORDER BY A.ID,B.ColumnName

The type of column "Change_Date" conflicts with the type of other columns specified in the UNPIVOT list

Having some problems with an Unpivot and not sure why. I understand the column types need to be the same and I think I have this sorted.
Table
CREATE TABLE [dbo].[zztmp1](
[Project_Number] [varchar](50) NULL,
[Changed_Design_Status] [varchar](50) NULL,
[Changed_Cost] [decimal](38, 4) NULL,
[Change_Date] [varchar](8) NULL
) ON [PRIMARY]
Script
select
Project_Number,
ColumnName, Value, Change_Date
from
(
select Project_Number,
Changed_Design_Status ,
cast(Changed_Cost as varchar(50)) Changed_Cost,
cast(Change_Date as varchar(50)) Change_Date
from zztmp1
) d
unpivot
(
Value FOR
ColumnName in ( Changed_Design_Status-- ,Changed_Cost
)
) unpiv;
When adding Change_Cost in I get the error :
Msg 8167, Level 16, State 1, Line 15
The type of column "Changed_Cost" conflicts with the type of other columns specified in the UNPIVOT list.
If I change the order and run with just change_Cost it works fine. It seems to be an issue when I have multiple columns, what am I mising.
Any advice appreciated.
Thanks
I find it so much easier to unpivot using cross apply:
select z.Project_Number, v.ColumnName, v.Value, z.Change_Date
from zztmp1 z outer apply
(values ('Changed_Cost', cast(Changed_Cost as varchar(50)) ),
('Changed_Design_Status', cast(Changed_Design_Status as varchar(50)) )
) v(ColumnName, Value);
In your case, it probably has to do with the type of Changed_Design_Status.

Get the Records as per the given OrderId only

I have a table with Primary key and auto incremented column lets say "HeaderFieldID".
Now i want to get the records as per the HeaderFieldID values.
Ex:
select *
from tblHeaderField
where HeaderFieldID in (2,1,3,4,6,5)
But,by default I am getting the records by HeaderFieldID asc order. But I want records as per the given HeaderFieldID's only.
Original Table
HeaderFieldID HFName DisplayName
1 OrgName1 disp1
2 OrgName2 disp2
3 OrgName3 disp3
4 OrgName4 disp4
5 OrgName5 disp5
6 OrgName6 disp6
Thanks in Advance
I don't know if you can order by IN, because you don't know order.
So first I would split data into rows from IN and then join it to your table.
DECLARE #table TABLE (ID INT IDENTITY(1,1) NOT NULL, NR INT)
--Prodvide data to lookup
DECLARE #givenText VARCHAR(100) = '2,1,3,4,5,6,7,8,9,10,11,12,13,14,15'
-- Split requested string into rows and add unique number
;WITH xmlData (xmlData) AS (
SELECT CAST('<x>'+REPLACE(#givenText, ',', '</x><x>')+'</x>' AS XML) AS xmlData
)
INSERT INTO #table (NR)
SELECT x.value('.','INT') AS NR
FROM xmlData
CROSS APPLY xmlData.xmlData.nodes('//x') AS func(x)
--Join tables to get result
SELECT tHF.*
FROM tblHeaderField AS tHF
INNER JOIN #table AS T
ON T.NR = tHF.HeaderFieldID
ORDER BY T.ID
Isn't clear where does this list come from (as a parameter of a stored procedure or hardcoded in the SQL statement?). Try this query:
select *
from tblHeaderField
where HeaderFieldID in (2,1,3,4,6,5)
ORDER BY
CHARINDEX(','+CAST(HeaderFieldID as varchar(100))+','
,',2,1,3,4,6,5,')
SQLFiddle demo
I have solved my query.
SELECT * FROM tblHeaderField
WHERE HeaderFieldID in (5,6,2,1,3,4,7,8,9,10,11,12,13,14,15)
ORDER BY CHARINDEX(CAST(HeaderFieldID AS VARCHAR), '5,6,2,1,3,4,7,8,9,10,11,12,13,14,15')

How do I return the column name in table where a null value exists?

I have a table of more than 2 million rows and over 100 columns. I need to run a query that checks if there are any null values in any row or column of the table and return an ID number where there is a null. I've thought about doing the following, but I was wondering if there is a more concise way of checking this?
SELECT [ID]
from [TABLE_NAME]
where
[COLUMN_1] is null
or [COLUMN_2] is null
or [COLUMN_3] is null or etc.
Your method is fine. If your challenge is writing out the where statement, then you can run a query like this:
select column_name+' is null or '
from information_schema.columns c
where c.table_name = 'table_name'
Then copy the results into a query window and use them for building the query.
I used SQL Server syntax for the query, because it looks like you are using SQL Server. Most databases support the INFORMATION_SCHEMA tables, but the syntax for string concatenation varies among databases. Remember to remove the final or at the end of the last comparison.
You can also copy the column list into Excel and use Excel formulas to create the list.
You can use something similar to the following:
declare #T table
(
ID int,
Name varchar(10),
Age int,
City varchar(10),
Zip varchar(10)
)
insert into #T values
(1, 'Alex', 32, 'Miami', NULL),
(2, NULL, 24, NULL, NULL)
;with xmlnamespaces('http://www.w3.org/2001/XMLSchema-instance' as ns)
select ID,
(
select *
from #T as T2
where T1.ID = T2.ID
for xml path('row'), elements xsinil, type
).value('count(/row/*[#ns:nil = "true"])', 'int') as NullCount
from #T as T1

Pivot String SQL

I am trying to Pivot this table whose name is #salida
IDJOB NAME DATE
1 Michael NULL
1 Aaron NULl
THe result which I want to obtain is
IDJOB DATE NAME1 NAME2
1 NULL Michael Aaron
My code is this
SELECT *
FROM #salida
PIVOT
(
MAX([Name]) FOR [Name] IN ([Name1],[Name2])
) PVT GROUP BY IdJob,Date,Name1,Name2 ;
SELECT * FROM #salida
The result which obtain is
IDJOB DATE NAME1 NAME2
1 NULL NULL NULL
#XabiIparra, see a mock up. you need to partition by the IdJob and then add the columns needed.
DECLARE #salida TABLE(idjob VARCHAR(100),[Name] VARCHAR(100),[DATE] DATE);
INSERT INTO #salida VALUES
(1,'Michael', NULL)
,(1,'Aaron', NULL)
,(2,'Banabas', NULL)
SELECT p.*
FROM
(
SELECT *
,'NAME'+CAST(ROW_NUMBER() OVER(PARTITION BY [idjob] ORDER BY NAME) AS varchar(100)) ColumnName
FROM #salida
)t
PIVOT
(
MAX([Name]) FOR ColumnName IN (NAME1,NAME2,NAME3,NAME4,NAME5 /*add as many as you need*/)
)p;
How about must using aggregation and min() and max()?
select idjob, date, min(name), max(name)
from #salida
group by idjob, date;
SQL tables represent unordered sets, so there is no ordering to the values (unless another column specifies the ordering). So, this is probably the simplest way to get two different values in the same row.