How to add DISTINCT to a column in select query - sql-server

Can you help me how to use DISTINCT in this query?
DECLARE #ReadData NVARCHAR(MAX);
SET #ReadData = 'SELECT ROW_NUMBER() OVER (ORDER BY RM.ReceiverDate) AS [S. No.]
,DISTINCT RM.ReceiverId
,RM.ReceiverDateas [Receiver Date]
,VM.VendorName as [Vendor Name]
,VM.VendorID
FROM Receiver RM
LEFT OUTER JOIN VendorMaster VM on VM.VendorID = RM.VendorId
WHERE ['+ #ColumnName + '] LIKE
CASE WHEN ' + #Filter+ ' = 0 THEN ''%' + #Value + '%'''+
' WHEN ' + #Filter + ' = 1 THEN '''+ #Value + '%'''+
' WHEN ' + #Filter + ' = 2 THEN ''%' + #Value +''' END
AND VM.IsActive = 1
AND RM.VendorID = CASE WHEN ' + CONVERT(VARCHAR, #VendorID) + ' = ''-1'' THEN RM.VendorID
ELSE '+ CONVERT(VARCHAR, #VendorID) +' END
AND (RM.ReceiverDate BETWEEN ' + CHAR(39) + CONVERT(VARCHAR(23), #FromDate, 126) + CHAR(39) +' AND ' + CHAR(39) + CONVERT(VARCHAR(23), #ToDate, 126) + CHAR(39) +')
ORDER BY RM.ReceiverDate '
My question is: how to add DISTINCT to the ReceiverId ?
I get this error:
Incorrect syntax near the keyword 'DISTINCT'.
in the C# code behind

with cte
as
(
Select ROW_NUMBER() OVER (PARTITION BY ReceiverId ORDER BY ReceiverId ) AS dupCount, *
from(
SELECT ROW_NUMBER() OVER (ORDER BY ReceivedDate) AS [S. No.]
,RM.ReceiverId
,RM.ReceiverName'
,VM.VendorName
, XYZ columns .....
From Receiver RM
LEFT OUTER JOIN VendorMaster VM on VM.VendorID = RM.VendorId
) tab
)
select S. No.
,ReceiverId
,ReceiverName
,VendorName
, XYZ columns
from cte
where dupcount=1;
try using cte.

DECLARE #ReadData NVARCHAR(MAX);
set #ReadData = 'SELECT *
,ROW_NUMBER() OVER (ORDER BY ReceivedDate) AS [S. No.]
FROM (SELECT DISTINCT ReceiverId,
ReceivedDate
,ReceiverName
, XYZ columns .....
From Receiver .........
INNER JOIN .......)'
You can't use the row_number and distinct on same level.

Related

T SQL Top 10 list of NULL Columns from a table

I'm using SQL Server 2014. I have a table with multiple columns in. Is it possible to dynamically list the top 10 columns within the table and the percent of the records in each column that is NULL? I do not want to hard code each column name in.
So the result set would be like:
Column Percent_Null
ABC 100
QWE 75
REW 65
TRW 50
I've started with the below, but how I do get this in a list? Ultimately the results need to go into a table for reporting.
DECLARE #SQL NVARCHAR(MAX)
SELECT #SQL = STUFF((
SELECT ', CAST(SUM(CASE WHEN ' + Quotename(C.COLUMN_NAME) + ' IS NULL THEN 1 ELSE 0 END) * 100.00
/#TotalCount AS INT) AS [' + C.COLUMN_NAME + ' NULL %]
'
FROM INFORMATION_SCHEMA.COLUMNS C
WHERE TABLE_NAME = 'tblMYTable'
AND TABLE_SCHEMA = 'dbo'
ORDER BY C.ORDINAL_POSITION
FOR XML PATH('')
,type
).value('.', 'nvarchar(max)'), 1, 2, '')
PRINT #SQL
Blargh, this is ugly, but it appears to do what you're after:
DECLARE #Table sysname = N'icp_yyclient',
#Schema sysname = N'dbo';
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
--First get a Count, which will be one column per column
SET #SQL = N'WITH Counts AS(' + #CRLF +
N' SELECT ' +
STUFF((SELECT N',' + #CRLF +
N' (COUNT(CASE WHEN ' + QUOTENAME(C.[name]) + N' IS NULL THEN 1 END) * 1.) / COUNT(*) AS ' + QUOTENAME(c.[name] + N'_PercNULL')
FROM sys.schemas s
JOIN sys.tables t ON s.schema_id = t.schema_id
JOIN sys.columns c ON t.object_id = c.object_id
WHERE s.name = #Schema
AND t.name = #Table
ORDER BY c.column_id
FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,14,N'') + #CRLF +
N' FROM ' + QUOTENAME(#Schema) + N'.' + QUOTENAME(#Table) + N')' + #CRLF +
--Now that we have a COUNT of column, we need to unpivot the data
N'SELECT TOP(10) V.*' + #CRLF +
N'FROM Counts C' + #CRLF +
N' CROSS APPLY(VALUES' +
STUFF((SELECT N',' + #CRLF +
N' (N' + QUOTENAME(C.[name],'''') + N', C.' + QUOTENAME(c.[name] + N'_PercNULL') + N')'
FROM sys.schemas s
JOIN sys.tables t ON s.schema_id = t.schema_id
JOIN sys.columns c ON t.object_id = c.object_id
WHERE s.name = #Schema
AND t.name = #Table
ORDER BY c.column_id
FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,26,N'') + N')V(ColumnName,ColumnPercNULL)' + #CRLF +
N'ORDER BY V.ColumnPercNULL DESC;';
--Uncommon to see the "mess". I strongly suggest ensuring you have retain CR/LF on in SSMS
--SELECT #SQL; --PRINT is limited to 4,000 characters, so probably too small.
EXEC sp_executesql #SQL;
For a table I have, (called Asset) this creates the following statement:
WITH Counts AS(
SELECT (COUNT(CASE WHEN [AssetID] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [AssetID_PercNULL],
(COUNT(CASE WHEN [AssetName] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [AssetName_PercNULL],
(COUNT(CASE WHEN [TypeID] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [TypeID_PercNULL],
(COUNT(CASE WHEN [SerialNumber] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [SerialNumber_PercNULL],
(COUNT(CASE WHEN [BarcodeNumber] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [BarcodeNumber_PercNULL],
(COUNT(CASE WHEN [Manufacturer] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [Manufacturer_PercNULL],
(COUNT(CASE WHEN [Model] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [Model_PercNULL],
(COUNT(CASE WHEN [LocationID] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [LocationID_PercNULL],
(COUNT(CASE WHEN [IPAddress] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [IPAddress_PercNULL],
(COUNT(CASE WHEN [PurchaseDate] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [PurchaseDate_PercNULL],
(COUNT(CASE WHEN [SetupDate] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [SetupDate_PercNULL],
(COUNT(CASE WHEN [DecommissionDate] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [DecommissionDate_PercNULL],
(COUNT(CASE WHEN [ReasonID] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [ReasonID_PercNULL],
(COUNT(CASE WHEN [DecommissionBy] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [DecommissionBy_PercNULL],
(COUNT(CASE WHEN [InvoiceID] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [InvoiceID_PercNULL],
(COUNT(CASE WHEN [IsVirtual] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [IsVirtual_PercNULL],
(COUNT(CASE WHEN [HostAssetID] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [HostAssetID_PercNULL],
(COUNT(CASE WHEN [DestroyDate] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [DestroyDate_PercNULL],
(COUNT(CASE WHEN [DestroyID] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [DestroyID_PercNULL],
(COUNT(CASE WHEN [DestroyedBy] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [DestroyedBy_PercNULL],
(COUNT(CASE WHEN [ValueExVAT] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [ValueExVAT_PercNULL],
(COUNT(CASE WHEN [VATValue] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [VATValue_PercNULL],
(COUNT(CASE WHEN [ValueIncVAT] IS NULL THEN 1 END) * 1.) / COUNT(*) AS [ValueIncVAT_PercNULL]
FROM [app].[Asset])
SELECT TOP(10) V.*
FROM Counts C
CROSS APPLY(VALUES(N'AssetID', C.[AssetID_PercNULL]),
(N'AssetName', C.[AssetName_PercNULL]),
(N'TypeID', C.[TypeID_PercNULL]),
(N'SerialNumber', C.[SerialNumber_PercNULL]),
(N'BarcodeNumber', C.[BarcodeNumber_PercNULL]),
(N'Manufacturer', C.[Manufacturer_PercNULL]),
(N'Model', C.[Model_PercNULL]),
(N'LocationID', C.[LocationID_PercNULL]),
(N'IPAddress', C.[IPAddress_PercNULL]),
(N'PurchaseDate', C.[PurchaseDate_PercNULL]),
(N'SetupDate', C.[SetupDate_PercNULL]),
(N'DecommissionDate', C.[DecommissionDate_PercNULL]),
(N'ReasonID', C.[ReasonID_PercNULL]),
(N'DecommissionBy', C.[DecommissionBy_PercNULL]),
(N'InvoiceID', C.[InvoiceID_PercNULL]),
(N'IsVirtual', C.[IsVirtual_PercNULL]),
(N'HostAssetID', C.[HostAssetID_PercNULL]),
(N'DestroyDate', C.[DestroyDate_PercNULL]),
(N'DestroyID', C.[DestroyID_PercNULL]),
(N'DestroyedBy', C.[DestroyedBy_PercNULL]),
(N'ValueExVAT', C.[ValueExVAT_PercNULL]),
(N'VATValue', C.[VATValue_PercNULL]),
(N'ValueIncVAT', C.[ValueIncVAT_PercNULL]))V(ColumnName,ColumnPercNULL)
ORDER BY V.ColumnPercNULL DESC;
This should give you some insight into how it works out the result.
Another way, using unpivot:
DECLARE #SCHEMANAME NVARCHAR(100) = 'dbo'
DECLARE #TABLENAME NVARCHAR(100) = 'your_table_name'
DECLARE #SQL NVARCHAR(MAX)
SELECT #SQL = 'SELECT TOP (10) * FROM (SELECT '+
STUFF (
(
SELECT ', CAST(SUM(CASE WHEN ' + Quotename(C.COLUMN_NAME) + ' IS NULL THEN 1 ELSE 0 END) * 100.00/COUNT(*) AS INT) AS ' + QUOTENAME(C.COLUMN_NAME, '"') + CHAR(13)
FROM INFORMATION_SCHEMA.COLUMNS C
WHERE TABLE_NAME = #TABLENAME
AND TABLE_SCHEMA = #SCHEMANAME
ORDER BY C.ORDINAL_POSITION
FOR XML PATH(''),type
).value('.', 'nvarchar(max)'),
1, 2, ''
)+' FROM '+QUOTENAME(#SCHEMANAME)+'.'+QUOTENAME(#TABLENAME)+') V1 UNPIVOT (NullsPerc FOR ColumnName IN ('+
STUFF (
(
SELECT ', '+ Quotename(C.COLUMN_NAME,'"') + CHAR(13)
FROM INFORMATION_SCHEMA.COLUMNS C
WHERE TABLE_NAME = #TABLENAME
AND TABLE_SCHEMA = #SCHEMANAME
ORDER BY C.ORDINAL_POSITION
FOR XML PATH(''),type
).value('.', 'nvarchar(max)'),
1, 2, ''
)+
')) AS UPVT
ORDER BY NULLSPERC DESC'
SELECT #SQL

Running SQL Server stored procedure(Update)

I get the following 2 errors when I want to run the following query in SQL Server
- how can I resolve the errors? Can you help me?
Run:
exec [dbo].[sp_siparisTest] 0,25,'','',''
Errors:
Msg 156, Level 15, State 1, Line 53
Incorrect syntax near the keyword 'ORDER'.
Msg 102, Level 15, State 1, Line 53
Incorrect syntax near '25'.
ALTER PROC [dbo].[sp_siparisTest]
(
#PageNo INT,
#RowCountPerPage INT,
#adsoyadfilter NVARCHAR(50),
#odemetip NVARCHAR(20),
#durumu NVARCHAR(20)
)
AS
BEGIN
DECLARE #devam_ nvarchar(max)
SET #devam_ ='SELECT
u.AdiSoyadi as AdSoyad,
ot.Adi as OdemeTipAdi,
sd.Adi as SiparisDurumAdi,
s.OlusturmaTarihi as OlusturmaTarihi,
s.GenelToplam as GenelToplam
FROM
Siparis as s with(NOLOCK)
inner join
SiparisDurum as sd with(NOLOCK) on s.Durumu=sd.Id
inner join
Uye as u with(NOLOCK) on s.Uye_Id=u.Id
inner join
OdemeTip as ot with(NOLOCK) on s.OdemeTip=ot.Id where '
IF(#adsoyadfilter !='')
SET #devam_ += '(u.AdiSoyadi LIKE ''%'' + '+ #adsoyadfilter +' + ''%'') AND'
IF(#odemetip != '')
SET #devam_ += ' ot.Id IN(SELECT Value FROM fn_Split( '+ #odemetip +' , '','')) AND'
IF(#odemetip != '')
SET #devam_ += ' s.Durumu IN(SELECT Value FROM fn_Split( '+#durumu +','',''))'
SET #devam_ +=' ORDER BY s.Id OFFSET (' + cast(#PageNo as nvarchar(255)) + ') ROWS FETCH NEXT (' + cast(#RowCountPerPage as nvarchar(255)) + ') ROWS ONLY'
END
EXECUTE sp_executesql #devam_
On your next to last line, change the SET to this:
SET #devam_ +=' ORDER BY s.Id OFFSET (' + cast(#PageNo as varchar(64)) + ') ROWS FETCH NEXT (' + cast(#RowCountPerPage as varchar(64)) + ') ROWS ONLY)'
You need a clause if all params are '' (1=1) and take #RowCountPerPage outside of the string:
ALTER PROC sp_siparisTest
(
#PageNo INT,
#RowCountPerPage INT,
#adsoyadfilter NVARCHAR(50),
#odemetip NVARCHAR(20),
#durumu NVARCHAR(20)
)
AS
BEGIN
DECLARE #devam_ nvarchar(max)
SET #devam_ = 'SELECT
u.AdiSoyadi as AdSoyad,
ot.Adi as OdemeTipAdi,
sd.Adi as SiparisDurumAdi,
s.OlusturmaTarihi as OlusturmaTarihi,
s.GenelToplam as GenelToplam
FROM
Siparis as s with(NOLOCK)
inner join
SiparisDurum as sd with(NOLOCK) on s.Durumu=sd.Id
inner join
Uye as u with(NOLOCK) on s.Uye_Id=u.Id
inner join
OdemeTip as ot with(NOLOCK) on s.OdemeTip=ot.Id where( '
IF(#adsoyadfilter !='')
SET #devam_ += '(u.AdiSoyadi LIKE ''%'' + #adsoyadfilter + ''%'') AND'
IF(#odemetip != '')
SET #devam_ += ' ot.Id IN(SELECT Value FROM fn_Split(#odemetip, '','')) AND'
IF(#odemetip != '')
SET #devam_ += ' AND s.Durumu IN(SELECT Value FROM fn_Split(#durumu,'','')) '
if #adsoyadfilter + #odemetip + #odemetip = '' SET #devam_ += '1=1) '
SET #devam_ +=' ORDER BY s.Id OFFSET (' + cast(#PageNo as nvarchar(255)) + ') ROWS FETCH NEXT (' + cast(#RowCountPerPage as nvarchar(255)) + ') ROWS ONLY'
END
EXECUTE sp_executesql #devam_

Concatenate columns of multiple columns and multiple rows into one varchar value, when no of columns is dynamic

So i have this dynamic query that returns a result set having dynamic number of columns like so:
In this result set we have columns for ID, FacilityName and cycleNum will always be there but number of task columns can vary Task1, Task2, Task3..... upto Taskn.
The final result set I need is as follows:
For this i have tried this query:
Select distinct FacilityName,
substring(
(
Select ',' + a
From (SELECT ID, FacilityName, 'Cycle-'+ cast(CycleNum as varchar)+'::' + 'Task1~' + cast(Task1 as varchar) + ',Task2~' + cast(Task2 as varchar) + ',Task3~' + cast(Task3 as varchar) + ';' as a FROM #tempTable) ST1
Where ST1.FacilityName = ST2.FacilityName
ORDER BY ST1.FacilityName
For XML PATH ('')
), 2, 1000) CycleData
From (SELECT ID, FacilityName, 'Cycle-'+ cast(CycleNum as varchar)+'::' + 'Task1~' + cast(Task1 as varchar) + ',Task2~' + cast(Task2 as varchar) + ',Task3~' + cast(Task3 as varchar)+ ';' as a FROM #tempTable) ST2
This will work with following test data:
create table #tempTable
(
ID int,
FacilityName varchar(50),
CycleNum int,
Task1 datetime,
Task2 datetime,
Task3 datetime
)
Insert into #tempTable values
(1, 'A', 1, convert(varchar(10), getdate(), 126), convert(varchar(10), dateadd(day,1,getdate()), 126), convert(varchar(10), dateadd(day,2,getdate()), 126)),
(2, 'A', 2, convert(varchar(10), getdate(), 126), convert(varchar(10), dateadd(day,1,getdate()), 126), convert(varchar(10), dateadd(day,2,getdate()), 126)),
(3, 'B', 1, convert(varchar(10), getdate(), 126), convert(varchar(10), dateadd(day,1,getdate()), 126), convert(varchar(10), dateadd(day,2,getdate()), 126)),
(4, 'B', 2, convert(varchar(10), getdate(), 126), convert(varchar(10), dateadd(day,1,getdate()), 126), convert(varchar(10), dateadd(day,2,getdate()), 126))
But I cant think of any way to extend this to use dynamic columns. The list of all columns is saved in a master table so we can get comma-separated list of columns from there if needed.
Here is a dynamic way
Slightly different approach from your static query. To make it dynamic, Use while loop or CURSOR to generate the Task1 + Task2 + ..TaskN. Then use it in Select query.
DECLARE #columns VARCHAR(50)='Task1,Task2,Task3', -- Pass the list of column names
#int INT = 1,
#sql VARCHAR(8000)
SET #sql = ' ;WITH cte
AS (SELECT *,
''Cycle-'' + Cast(CycleNum AS VARCHAR(10)) + ''::'' '
WHILE #int <= Len(#columns) - Len(Replace(#columns, ',', '')) -- To find the number of Tasks in list
BEGIN
SET #sql += + '+''Task' + Cast(#int AS VARCHAR(10))
+ '~''+' + 'Cast(Task'
+ Cast(#int AS VARCHAR(10))
+ ' AS VARCHAR(50)) + '','''
SET #int += 1
END
SET #sql += ' AS concat_dates
FROM #tempTable)
SELECT DISTINCT FacilityName,
LEFT(CycleData, Len(CycleData) - 1)
FROM cte a
CROSS apply(SELECT b.concat_dates + '',''
FROM cte b
WHERE a.FacilityName = b.FacilityName
FOR xml path('''')) cs (CycleData)
'
--print #sql -- uncomment it to debug if you have any error when executing dynamic code
EXEC (#sql)
Not to worry about the usage of While Loop/CURSOR since we are not doing any resource intensive operations inside the loop.
Static Query will looking like this
;WITH cte
AS (SELECT *,
'Cycle-' + Cast(CycleNum AS VARCHAR(10))
+ '::' + 'Task1~' + Cast(Task1 AS VARCHAR(50))
+ ',' + 'Task2~' + Cast(Task2 AS VARCHAR(50))
+ ',' AS concat_dates
FROM #tempTable)
SELECT DISTINCT FacilityName,
LEFT(CycleData, Len(CycleData) - 1)
FROM cte a
CROSS apply(SELECT b.concat_dates + ','
FROM cte b
WHERE a.FacilityName = b.FacilityName
FOR xml path('')) cs (CycleData)
Use system tables. I prefer short and effective solutions :). This is guide, I'm sure you can finish it yourself with concentating strings (if you are not sure, add comment and I will add whole code or more description).
declare #columns varchar(max)
SELECT #columns = isnull(#columns + '+', '') + '''' + COLUMN_NAME + '~'' + Cast(' + COLUMN_NAME + ' as varchar(50))'
FROM tempdb.INFORMATION_SCHEMA.COLUMNS c
WHERE c.TABLE_NAME like '#tempTable%'
AND c.COLUMN_NAME LIKE 'Task%' -- filter columns you are interested in
declare #sql varchar(4000) = 'select *, ' + #columns + ' from #tempTable'
print #sql
exec (#sql)

Pivot in sql server returns error "incorrect syntax near the keyword 'for': The DUPLICATE has not the answer [duplicate]

I'm looking for an efficient way to convert rows to columns in SQL server, I heard that PIVOT is not very fast, and I need to deal with lot of records.
This is my example:
-------------------------------
| Id | Value | ColumnName |
-------------------------------
| 1 | John | FirstName |
| 2 | 2.4 | Amount |
| 3 | ZH1E4A | PostalCode |
| 4 | Fork | LastName |
| 5 | 857685 | AccountNumber |
-------------------------------
This is my result:
---------------------------------------------------------------------
| FirstName |Amount| PostalCode | LastName | AccountNumber |
---------------------------------------------------------------------
| John | 2.4 | ZH1E4A | Fork | 857685 |
---------------------------------------------------------------------
How can I build the result?
There are several ways that you can transform data from multiple rows into columns.
Using PIVOT
In SQL Server you can use the PIVOT function to transform the data from rows to columns:
select Firstname, Amount, PostalCode, LastName, AccountNumber
from
(
select value, columnname
from yourtable
) d
pivot
(
max(value)
for columnname in (Firstname, Amount, PostalCode, LastName, AccountNumber)
) piv;
See Demo.
Pivot with unknown number of columnnames
If you have an unknown number of columnnames that you want to transpose, then you can use dynamic SQL:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(ColumnName)
from yourtable
group by ColumnName, id
order by id
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = N'SELECT ' + #cols + N' from
(
select value, ColumnName
from yourtable
) x
pivot
(
max(value)
for ColumnName in (' + #cols + N')
) p '
exec sp_executesql #query;
See Demo.
Using an aggregate function
If you do not want to use the PIVOT function, then you can use an aggregate function with a CASE expression:
select
max(case when columnname = 'FirstName' then value end) Firstname,
max(case when columnname = 'Amount' then value end) Amount,
max(case when columnname = 'PostalCode' then value end) PostalCode,
max(case when columnname = 'LastName' then value end) LastName,
max(case when columnname = 'AccountNumber' then value end) AccountNumber
from yourtable
See Demo.
Using multiple joins
This could also be completed using multiple joins, but you will need some column to associate each of the rows which you do not have in your sample data. But the basic syntax would be:
select fn.value as FirstName,
a.value as Amount,
pc.value as PostalCode,
ln.value as LastName,
an.value as AccountNumber
from yourtable fn
left join yourtable a
on fn.somecol = a.somecol
and a.columnname = 'Amount'
left join yourtable pc
on fn.somecol = pc.somecol
and pc.columnname = 'PostalCode'
left join yourtable ln
on fn.somecol = ln.somecol
and ln.columnname = 'LastName'
left join yourtable an
on fn.somecol = an.somecol
and an.columnname = 'AccountNumber'
where fn.columnname = 'Firstname'
This is rather a method than just a single script but gives you much more flexibility.
First of all There are 3 objects:
User defined TABLE type [ColumnActionList] -> holds data as
parameter
SP [proc_PivotPrepare] -> prepares our data
SP [proc_PivotExecute] -> execute the script
CREATE TYPE [dbo].[ColumnActionList] AS TABLE
(
[ID] [smallint] NOT NULL,
[ColumnName] nvarchar NOT NULL,
[Action] nchar NOT NULL
);
GO
CREATE PROCEDURE [dbo].[proc_PivotPrepare]
(
#DB_Name nvarchar(128),
#TableName nvarchar(128)
)
AS
SELECT #DB_Name = ISNULL(#DB_Name,db_name())
DECLARE #SQL_Code nvarchar(max)
DECLARE #MyTab TABLE (ID smallint identity(1,1), [Column_Name] nvarchar(128), [Type] nchar(1), [Set Action SQL] nvarchar(max));
SELECT #SQL_Code = 'SELECT [<| SQL_Code |>] = '' '' '
+ 'UNION ALL '
+ 'SELECT ''----------------------------------------------------------------------------------------------------'' '
+ 'UNION ALL '
+ 'SELECT ''-----| Declare user defined type [ID] / [ColumnName] / [PivotAction] '' '
+ 'UNION ALL '
+ 'SELECT ''----------------------------------------------------------------------------------------------------'' '
+ 'UNION ALL '
+ 'SELECT ''DECLARE #ColumnListWithActions ColumnActionList;'''
+ 'UNION ALL '
+ 'SELECT ''----------------------------------------------------------------------------------------------------'' '
+ 'UNION ALL '
+ 'SELECT ''-----| Set [PivotAction] (''''S'''' as default) to select dimentions and values '' '
+ 'UNION ALL '
+ 'SELECT ''-----|'''
+ 'UNION ALL '
+ 'SELECT ''-----| ''''S'''' = Stable column || ''''D'''' = Dimention column || ''''V'''' = Value column '' '
+ 'UNION ALL '
+ 'SELECT ''----------------------------------------------------------------------------------------------------'' '
+ 'UNION ALL '
+ 'SELECT ''INSERT INTO #ColumnListWithActions VALUES ('' + CAST( ROW_NUMBER() OVER (ORDER BY [NAME]) as nvarchar(10)) + '', '' + '''''''' + [NAME] + ''''''''+ '', ''''S'''');'''
+ 'FROM [' + #DB_Name + '].sys.columns '
+ 'WHERE object_id = object_id(''[' + #DB_Name + ']..[' + #TableName + ']'') '
+ 'UNION ALL '
+ 'SELECT ''----------------------------------------------------------------------------------------------------'' '
+ 'UNION ALL '
+ 'SELECT ''-----| Execute sp_PivotExecute with parameters: columns and dimentions and main table name'' '
+ 'UNION ALL '
+ 'SELECT ''----------------------------------------------------------------------------------------------------'' '
+ 'UNION ALL '
+ 'SELECT ''EXEC [dbo].[sp_PivotExecute] #ColumnListWithActions, ' + '''''' + #TableName + '''''' + ';'''
+ 'UNION ALL '
+ 'SELECT ''----------------------------------------------------------------------------------------------------'' '
EXECUTE SP_EXECUTESQL #SQL_Code;
GO
CREATE PROCEDURE [dbo].[sp_PivotExecute]
(
#ColumnListWithActions ColumnActionList ReadOnly
,#TableName nvarchar(128)
)
AS
--#######################################################################################################################
--###| Step 1 - Select our user-defined-table-variable into temp table
--#######################################################################################################################
IF OBJECT_ID('tempdb.dbo.#ColumnListWithActions', 'U') IS NOT NULL DROP TABLE #ColumnListWithActions;
SELECT * INTO #ColumnListWithActions FROM #ColumnListWithActions;
--#######################################################################################################################
--###| Step 2 - Preparing lists of column groups as strings:
--#######################################################################################################################
DECLARE #ColumnName nvarchar(128)
DECLARE #Destiny nchar(1)
DECLARE #ListOfColumns_Stable nvarchar(max)
DECLARE #ListOfColumns_Dimension nvarchar(max)
DECLARE #ListOfColumns_Variable nvarchar(max)
--############################
--###| Cursor for List of Stable Columns
--############################
DECLARE ColumnListStringCreator_S CURSOR FOR
SELECT [ColumnName]
FROM #ColumnListWithActions
WHERE [Action] = 'S'
OPEN ColumnListStringCreator_S;
FETCH NEXT FROM ColumnListStringCreator_S
INTO #ColumnName
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #ListOfColumns_Stable = ISNULL(#ListOfColumns_Stable, '') + ' [' + #ColumnName + '] ,';
FETCH NEXT FROM ColumnListStringCreator_S INTO #ColumnName
END
CLOSE ColumnListStringCreator_S;
DEALLOCATE ColumnListStringCreator_S;
--############################
--###| Cursor for List of Dimension Columns
--############################
DECLARE ColumnListStringCreator_D CURSOR FOR
SELECT [ColumnName]
FROM #ColumnListWithActions
WHERE [Action] = 'D'
OPEN ColumnListStringCreator_D;
FETCH NEXT FROM ColumnListStringCreator_D
INTO #ColumnName
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #ListOfColumns_Dimension = ISNULL(#ListOfColumns_Dimension, '') + ' [' + #ColumnName + '] ,';
FETCH NEXT FROM ColumnListStringCreator_D INTO #ColumnName
END
CLOSE ColumnListStringCreator_D;
DEALLOCATE ColumnListStringCreator_D;
--############################
--###| Cursor for List of Variable Columns
--############################
DECLARE ColumnListStringCreator_V CURSOR FOR
SELECT [ColumnName]
FROM #ColumnListWithActions
WHERE [Action] = 'V'
OPEN ColumnListStringCreator_V;
FETCH NEXT FROM ColumnListStringCreator_V
INTO #ColumnName
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #ListOfColumns_Variable = ISNULL(#ListOfColumns_Variable, '') + ' [' + #ColumnName + '] ,';
FETCH NEXT FROM ColumnListStringCreator_V INTO #ColumnName
END
CLOSE ColumnListStringCreator_V;
DEALLOCATE ColumnListStringCreator_V;
SELECT #ListOfColumns_Variable = LEFT(#ListOfColumns_Variable, LEN(#ListOfColumns_Variable) - 1);
SELECT #ListOfColumns_Dimension = LEFT(#ListOfColumns_Dimension, LEN(#ListOfColumns_Dimension) - 1);
SELECT #ListOfColumns_Stable = LEFT(#ListOfColumns_Stable, LEN(#ListOfColumns_Stable) - 1);
--#######################################################################################################################
--###| Step 3 - Preparing table with all possible connections between Dimension columns excluding NULLs
--#######################################################################################################################
DECLARE #DIM_TAB TABLE ([DIM_ID] smallint, [ColumnName] nvarchar(128))
INSERT INTO #DIM_TAB
SELECT [DIM_ID] = ROW_NUMBER() OVER(ORDER BY [ColumnName]), [ColumnName] FROM #ColumnListWithActions WHERE [Action] = 'D';
DECLARE #DIM_ID smallint;
SELECT #DIM_ID = 1;
DECLARE #SQL_Dimentions nvarchar(max);
IF OBJECT_ID('tempdb.dbo.##ALL_Dimentions', 'U') IS NOT NULL DROP TABLE ##ALL_Dimentions;
SELECT #SQL_Dimentions = 'SELECT [xxx_ID_xxx] = ROW_NUMBER() OVER (ORDER BY ' + #ListOfColumns_Dimension + '), ' + #ListOfColumns_Dimension
+ ' INTO ##ALL_Dimentions '
+ ' FROM (SELECT DISTINCT' + #ListOfColumns_Dimension + ' FROM ' + #TableName
+ ' WHERE ' + (SELECT [ColumnName] FROM #DIM_TAB WHERE [DIM_ID] = #DIM_ID) + ' IS NOT NULL ';
SELECT #DIM_ID = #DIM_ID + 1;
WHILE #DIM_ID <= (SELECT MAX([DIM_ID]) FROM #DIM_TAB)
BEGIN
SELECT #SQL_Dimentions = #SQL_Dimentions + 'AND ' + (SELECT [ColumnName] FROM #DIM_TAB WHERE [DIM_ID] = #DIM_ID) + ' IS NOT NULL ';
SELECT #DIM_ID = #DIM_ID + 1;
END
SELECT #SQL_Dimentions = #SQL_Dimentions + ' )x';
EXECUTE SP_EXECUTESQL #SQL_Dimentions;
--#######################################################################################################################
--###| Step 4 - Preparing table with all possible connections between Stable columns excluding NULLs
--#######################################################################################################################
DECLARE #StabPos_TAB TABLE ([StabPos_ID] smallint, [ColumnName] nvarchar(128))
INSERT INTO #StabPos_TAB
SELECT [StabPos_ID] = ROW_NUMBER() OVER(ORDER BY [ColumnName]), [ColumnName] FROM #ColumnListWithActions WHERE [Action] = 'S';
DECLARE #StabPos_ID smallint;
SELECT #StabPos_ID = 1;
DECLARE #SQL_MainStableColumnTable nvarchar(max);
IF OBJECT_ID('tempdb.dbo.##ALL_StableColumns', 'U') IS NOT NULL DROP TABLE ##ALL_StableColumns;
SELECT #SQL_MainStableColumnTable = 'SELECT xxx_ID_xxx = ROW_NUMBER() OVER (ORDER BY ' + #ListOfColumns_Stable + '), ' + #ListOfColumns_Stable
+ ' INTO ##ALL_StableColumns '
+ ' FROM (SELECT DISTINCT' + #ListOfColumns_Stable + ' FROM ' + #TableName
+ ' WHERE ' + (SELECT [ColumnName] FROM #StabPos_TAB WHERE [StabPos_ID] = #StabPos_ID) + ' IS NOT NULL ';
SELECT #StabPos_ID = #StabPos_ID + 1;
WHILE #StabPos_ID <= (SELECT MAX([StabPos_ID]) FROM #StabPos_TAB)
BEGIN
SELECT #SQL_MainStableColumnTable = #SQL_MainStableColumnTable + 'AND ' + (SELECT [ColumnName] FROM #StabPos_TAB WHERE [StabPos_ID] = #StabPos_ID) + ' IS NOT NULL ';
SELECT #StabPos_ID = #StabPos_ID + 1;
END
SELECT #SQL_MainStableColumnTable = #SQL_MainStableColumnTable + ' )x';
EXECUTE SP_EXECUTESQL #SQL_MainStableColumnTable;
--#######################################################################################################################
--###| Step 5 - Preparing table with all options ID
--#######################################################################################################################
DECLARE #FULL_SQL_1 NVARCHAR(MAX)
SELECT #FULL_SQL_1 = ''
DECLARE #i smallint
IF OBJECT_ID('tempdb.dbo.##FinalTab', 'U') IS NOT NULL DROP TABLE ##FinalTab;
SELECT #FULL_SQL_1 = 'SELECT t.*, dim.[xxx_ID_xxx] '
+ ' INTO ##FinalTab '
+ 'FROM ' + #TableName + ' t '
+ 'JOIN ##ALL_Dimentions dim '
+ 'ON t.' + (SELECT [ColumnName] FROM #DIM_TAB WHERE [DIM_ID] = 1) + ' = dim.' + (SELECT [ColumnName] FROM #DIM_TAB WHERE [DIM_ID] = 1);
SELECT #i = 2
WHILE #i <= (SELECT MAX([DIM_ID]) FROM #DIM_TAB)
BEGIN
SELECT #FULL_SQL_1 = #FULL_SQL_1 + ' AND t.' + (SELECT [ColumnName] FROM #DIM_TAB WHERE [DIM_ID] = #i) + ' = dim.' + (SELECT [ColumnName] FROM #DIM_TAB WHERE [DIM_ID] = #i)
SELECT #i = #i +1
END
EXECUTE SP_EXECUTESQL #FULL_SQL_1
--#######################################################################################################################
--###| Step 6 - Selecting final data
--#######################################################################################################################
DECLARE #STAB_TAB TABLE ([STAB_ID] smallint, [ColumnName] nvarchar(128))
INSERT INTO #STAB_TAB
SELECT [STAB_ID] = ROW_NUMBER() OVER(ORDER BY [ColumnName]), [ColumnName]
FROM #ColumnListWithActions WHERE [Action] = 'S';
DECLARE #VAR_TAB TABLE ([VAR_ID] smallint, [ColumnName] nvarchar(128))
INSERT INTO #VAR_TAB
SELECT [VAR_ID] = ROW_NUMBER() OVER(ORDER BY [ColumnName]), [ColumnName]
FROM #ColumnListWithActions WHERE [Action] = 'V';
DECLARE #y smallint;
DECLARE #x smallint;
DECLARE #z smallint;
DECLARE #FinalCode nvarchar(max)
SELECT #FinalCode = ' SELECT ID1.*'
SELECT #y = 1
WHILE #y <= (SELECT MAX([xxx_ID_xxx]) FROM ##FinalTab)
BEGIN
SELECT #z = 1
WHILE #z <= (SELECT MAX([VAR_ID]) FROM #VAR_TAB)
BEGIN
SELECT #FinalCode = #FinalCode + ', [ID' + CAST((#y) as varchar(10)) + '.' + (SELECT [ColumnName] FROM #VAR_TAB WHERE [VAR_ID] = #z) + '] = ID' + CAST((#y + 1) as varchar(10)) + '.' + (SELECT [ColumnName] FROM #VAR_TAB WHERE [VAR_ID] = #z)
SELECT #z = #z + 1
END
SELECT #y = #y + 1
END
SELECT #FinalCode = #FinalCode +
' FROM ( SELECT * FROM ##ALL_StableColumns)ID1';
SELECT #y = 1
WHILE #y <= (SELECT MAX([xxx_ID_xxx]) FROM ##FinalTab)
BEGIN
SELECT #x = 1
SELECT #FinalCode = #FinalCode
+ ' LEFT JOIN (SELECT ' + #ListOfColumns_Stable + ' , ' + #ListOfColumns_Variable
+ ' FROM ##FinalTab WHERE [xxx_ID_xxx] = '
+ CAST(#y as varchar(10)) + ' )ID' + CAST((#y + 1) as varchar(10))
+ ' ON 1 = 1'
WHILE #x <= (SELECT MAX([STAB_ID]) FROM #STAB_TAB)
BEGIN
SELECT #FinalCode = #FinalCode + ' AND ID1.' + (SELECT [ColumnName] FROM #STAB_TAB WHERE [STAB_ID] = #x) + ' = ID' + CAST((#y+1) as varchar(10)) + '.' + (SELECT [ColumnName] FROM #STAB_TAB WHERE [STAB_ID] = #x)
SELECT #x = #x +1
END
SELECT #y = #y + 1
END
SELECT * FROM ##ALL_Dimentions;
EXECUTE SP_EXECUTESQL #FinalCode;
From executing the first query (by passing source DB and table name) you will get a pre-created execution query for the second SP, all you have to do is define is the column from your source:
+ Stable
+ Value (will be used to concentrate values based on that)
+ Dim (column you want to use to pivot by)
Names and datatypes will be defined automatically!
I cant recommend it for any production environments but does the job for adhoc BI requests.
I modified Taryn's answer ("Pivot with unknown number of columnnames" version) to show more than 1 row in the result. This requires to have an additional "Group" column
DROP TABLE #yourtable
CREATE table #yourtable
([Id] int,[Group] int, [Value] varchar(6), [ColumnName] varchar(13))
;
INSERT INTO #yourtable
([Id],[Group], [Value], [ColumnName])
VALUES
(1,1, 'John', 'FirstName'),
(2,1, '2.4', 'Amount'),
(3,1, 'ZH1E4A', 'PostalCode'),
(4,1, 'Fork', 'LastName'),
(5,1, '857685', 'AccountNumber'),
(6,2, 'Pedro', 'FirstName'),
(7,2, '5.1', 'Amount'),
(8,2, '123456', 'PostalCode'),
(9,2, 'Torres', 'LastName'),
(10,2, '857686', 'AccountNumber')
;
;
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(ColumnName)
from #yourtable
group by [Group], ColumnName, id
having [group] = (SELECT TOP 1 MIN([Group])FROM #yourtable)
order by id
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = N'SELECT ' + #cols + N' from
(
select value, ColumnName,[Group]
from #yourtable
GROUP BY [Group],ColumnName,Value
) x
pivot
(
max(value)
for ColumnName in (' + #cols + N')
) p '
exec sp_executesql #query;
Please try
CREATE TABLE pvt (Present int, [Absent] int);
GO
INSERT INTO pvt VALUES (10,40);
GO
--Unpivot the table.
SELECT Code, Value
FROM
(SELECT Present, Absent
FROM pvt) p
UNPIVOT
(Value FOR Code IN
(Present, [Absent])
)AS unpvt;
GO
DROP TABLE pvt
One more option which could be very useful is using CROSS APPLY
-- Original data
SELECT * FROM (VALUES ('1', 1, 2, 3),('2', 11, 22, 33)) AS Stage(id,col1,col2,col3)
-- row to columns using CROSS APPLY
SELECT Stage.id,v.idd, v.colc
FROM (VALUES ('1', 1, 2, 3),('2', 11, 22, 33)) AS Stage(id,col1,col2,col3)
CROSS APPLY (VALUES ('col1', col1),('col2', col2),('col3', col3)) AS v(idd,colc)
GO

SQL Server Syntax Error on PIVOT

Can anyone please help me with the PIVOT table syntax error as I am using this for the First time.
DECLARE #sql AS varchar(max)<br/>
DECLARE #pivot_list AS varchar(max) <br/>
DECLARE #select_list AS varchar(max) <br/>
SELECT #pivot_list = COALESCE(#pivot_list + ', ', '') + '[' + CONVERT(varchar, STATE_NAME) + ']'<br/>
,#select_list = COALESCE(#select_list + ', ', '') + '[' + CONVERT(varchar, STATE_NAME) + '] AS [' + CONVERT(varchar, STATE_NAME) + ']'
FROM (
SELECT DISTINCT name as STATE_NAME
FROM k12_dms_states
) AS PIVOT_CODES
SET #sql = '
SELECT COUNT(k12_dms_contacts_institution_jobtitles.id) as total_count
,k12_dms_job_titles.title as job_title,' + #select_list + '
FROM k12_dms_institution_master
INNER JOIN k12_dms_contacts_institution_jobtitles ON k12_dms_institution_master.id = k12_dms_contacts_institution_jobtitles.inst_id
INNER JOIN k12_dms_job_titles ON k12_dms_job_titles.id = k12_dms_contacts_institution_jobtitles.job_title_id
GROUP BY k12_dms_job_titles.title
PIVOT (
total_count
FOR STATE_NAME IN (
' + #pivot_list + '
)
) AS pvt
'
PRINT #sql
EXEC (#sql)
I am getting this error: -
Msg 156, Level 15, State 1, Line 8
Incorrect syntax near the keyword 'PIVOT'.
PIVOT belongs in the FROM clause. It needs to occur before any GROUP BY clause.
(Further edits based on commenting, to try to correct):
SET #sql = '
SELECT
k12_dms_job_titles.title as job_title,' + #select_list + '
FROM k12_dms_institution_master
INNER JOIN k12_dms_contacts_institution_jobtitles ON k12_dms_institution_master.id = k12_dms_contacts_institution_jobtitles.inst_id
INNER JOIN k12_dms_job_titles ON k12_dms_job_titles.id = k12_dms_contacts_institution_jobtitles.job_title_id
PIVOT (
COUNT(k12_dms_contacts_institution_jobtitles.id)
FOR STATE_NAME IN (
' + #pivot_list + '
)
) AS pvt
'

Resources