Pivot table without knowing row values - sql-server

This is my table - Select ItemName, ItemDescription from MyTable
I do not know what the values would be in ItemName or ItemDescription.
Would it be possible to display the data so that ItemName would be created as columns and the ItemDescription be the row value?

Requires mssql 2008+
create table mytable( ItemName varchar(10), ItemDescription varchar(10))
insert mytable values('item 1', 'desc1')
insert mytable values('item 2', 'desc2')
insert mytable values('item 1', 'desc2')
declare #list varchar(2000)
;with cte
as(
select distinct top 100 percent replace(replace(itemname, ']', ''), '[', '') itemname
from mytable
order by itemname
)
select #list = coalesce(#list + ',' + '['+itemname+']', '['+itemname+']') from cte
declare #sql varchar(4000)
set #sql =
'
select * from
(
select replace(replace(itemname, '']'', ''''), ''['', '''') itemname, ItemDescription, row_number() over (partition by ItemName order by ItemDescription) id from mytable
) a
PIVOT (MAX([ItemDescription]) FOR [itemname] IN ('+#list+')) AS pvt'
exec (#sql)
Result:
id item 1 item 2
1 desc1 desc2
2 desc2 NULL

Related

How To Select specific column As Row?

I have 2 tables Phone_record and customer
In my phone records tables I have two columns company_name and ModelNo
Now I want to show Company_name as my main column name
And in this column I want to show models of that company like this
Company 1 company2.....
Model1 model1
Model2 model2
How to write this query?
Here is a fully functional example of how you might do this.
if OBJECT_ID('tempdb..#Something') is not null
drop table #Something
create table #Something
(
ID int,
Subject1 varchar(50)
)
insert #Something
select 10868952, 'Some Subject' union all
select 10868952, 'Another one' union all
select 10868952, 'This Subject' union all
select 10868952, 'Science' union all
select 12345, 'My Subject'
declare #MaxCols int
declare #StaticPortion nvarchar(2000) =
'with OrderedResults as
(
select *, ROW_NUMBER() over(partition by ID order by Subject1) as RowNum
from #Something
)
select ID';
declare #DynamicPortion nvarchar(max) = '';
declare #FinalStaticPortion nvarchar(2000) = ' from OrderedResults Group by ID order by ID';
with E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --100 rows
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E2
)
select #DynamicPortion = #DynamicPortion +
', MAX(Case when RowNum = ' + CAST(N as varchar(6)) + ' then Subject1 end) as Subject' + CAST(N as varchar(6)) + CHAR(10)
from cteTally t
where t.N <=
(
select top 1 Count(*)
from #Something
group by ID
order by COUNT(*) desc
)
--select #StaticPortion + #DynamicPortion + #FinalStaticPortion
declare #SqlToExecute nvarchar(max) = #StaticPortion + #DynamicPortion + #FinalStaticPortion;
exec sp_executesql #SqlToExecute

Pivot with Group by on SQL

I'm create sql syntax which create pivot Group By Product based on Category
CREATE TABLE #Product ( Product varchar(10),Category varchar(10),Stock int)
INSERT INTO #Product Values ('Item A','CatA',10)
INSERT INTO #Product Values ('Item A','CatB',5)
INSERT INTO #Product Values ('Item B','CatA',3)
INSERT INTO #Product Values ('Item B','CatB',5)
INSERT INTO #Product Values ('Item B','CatC',7)
INSERT INTO #Product Values ('Item B','CatD',10)
SELECT *
FROM
(
SELECT Product,Category,Stock
FROM #Product A
) src
pivot
(
SUM(Stock)
for Category in ([CatA], [CatB], [CatC],[CatD])
) piv;
DROP TABLE #Product
Result of Query
Product CatA CatB CatC CatD
Item A 10 5 NULL NULL
Item B 3 5 7 10
Result trying to achieve is
Product Cat1 Stock1 Cat2 Stock2 Cat3 Stock3 Cat4 Stock4
Item A CatA 10 CatB 5 CatC 0 CatD 0
Item B CatA 3 CatB 5 CatC 7 CatD 10
Thanks for the help
You need to create all combinations of Product and Category first. Then do a LEFT JOIN on #Product to get the Stock. Finally, use the result to pivot the data.
Since I'm not familiar with the PIVOT command, I used another technique called Dynamic Crosstab
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql =
'SELECT
Product' + CHAR(10);
SELECT #sql = #sql +
STUFF((
SELECT
' ,MAX(CASE WHEN RN = ' + CONVERT(VARCHAR(3), t.RN) + ' THEN Category END) AS ' + QUOTENAME('Cat' + CONVERT(VARCHAR(3), t.RN)) + CHAR(10) +
' ,MAX(CASE WHEN RN = ' + CONVERT(VARCHAR(3), t.RN) + ' THEN Stock END) AS ' + QUOTENAME('Stock' + CONVERT(VARCHAR(3), t.RN)) + CHAR(10)
FROM (
SELECT DISTINCT
RN = ROW_NUMBER() OVER(PARTITION BY Product ORDER BY(SELECT NULL))
FROM #Product
) t
FOR XML PATH('')
), 1, 1, ' ');
SELECT #sql = #sql +
'FROM(
SELECT
p1.Product,
p1.Category,
Stock = ISNULL(p2.Stock, 0),
RN = ROW_NUMBER() OVER(PARTITION BY p1.Product ORDER BY p1.Category)
FROM (
SELECT
t1.Product, t2.Category
FROM (
SELECT DISTINCT Product FROM #Product
) t1
CROSS JOIN (
SELECT DISTINCT Category FROM #Product
) t2
) p1
LEFT JOIN #Product p2
ON p1.Product = p2.Product
AND p1.Category = p2.Category
)t
GROUP BY Product;';
PRINT #sql;
EXEC sp_executesql #sql;
ONLINE DEMO

How do i pivot a table?

I have a dynamic single row Table like:
PersonId|FirstName|LastName|Address|PhoneNumber
-----------------------------------------------
1 Anuj Tamrakar NY +525418
I want to pivot this table and want an output in temp table like:
PersonalDetails|Value
----------------------
PersonId 1
FirstName Anuj
LastName Tamrakar
Address NY
PhoneNumber +525418
The first Table is a dynamic single row temp table. For this example, I have 5 columns. I may have more or less columns depending on my criteria
You actually want to UNPIVOT:
SELECT PersonalDetails, Value
FROM
(SELECT CAST([PersonId] AS VARCHAR(MAX)) AS [PersonId],
CAST([FirstName] AS VARCHAR(MAX)) AS [FirstName],
CAST([LastName] AS VARCHAR(MAX)) AS [LastName],
CAST([Address] AS VARCHAR(MAX)) AS [Address],
CAST([PhoneNumber] AS VARCHAR(MAX)) AS [PhoneNumber]
FROM mytable) p
UNPIVOT
(Value FOR PersonalDetails IN
([PersonId], [FirstName], [LastName], [Address], [PhoneNumber])
) AS unpvt;
All 'to-be-unpivoted' fields have to be of the same type, hence the use of CAST.
Demo here
For a dynamic number of columns you have to use dynamic sql:
DECLARE #cols VARCHAR(MAX) = ''
DECLARE #cast_cols VARCHAR(MAX) = ''
DECLARE #qry VARCHAR(MAX)
SELECT #cols = #cols + ',[' + COLUMN_NAME + ']'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'mytable' AND TABLE_SCHEMA='dbo'
SELECT #cast_cols = #cast_cols + ',CAST([' + COLUMN_NAME + '] AS VARCHAR(MAX)) AS [' + COLUMN_NAME + ']'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'mytable' AND TABLE_SCHEMA='dbo'
SET #cols = STUFF(#cols, 1, 1, '')
SET #cast_cols = STUFF(#cast_cols, 1, 1, '')
SET #qry = 'SELECT PersonalDetails, Value FROM ('
+ #cast_cols +
'FROM mytable) p
UNPIVOT
(Value FOR PersonalDetails IN (' + #cols + ')
) AS unpvt'
EXEC (#qry)
If you really have a single row in the original table, then you can use a series of UNION operations to get your output:
SELECT 'PersonId' AS PersonalDetails, PersonId AS Value
FROM yourTable
UNION ALL
SELECT 'FirstName' AS PersonalDetails, FirstName AS Value
FROM yourTable
UNION ALL
SELECT 'LastName' AS PersonalDetails, LastName AS Value
FROM yourTable
UNION ALL
SELECT 'Address' AS PersonalDetails, Address AS Value
FROM yourTable
UNION ALL
SELECT 'PhoneNumber' AS PersonalDetails, PhoneNumber AS Value
FROM yourTable
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID('dbo.yourTableName')
This gives you your column names. You simply insert the column names in your new table and use ``, insert into temp(PersonalDetails, Value) values(column1,select column1 from SingleRowTable

SQL Server results into a single string with counter

I have a table like this:
Product_Id Description
---------------------------
BX01 Desc 1
BxX1 Desc 2
Dss3 Desc 3
HHXY Desc 4
I want the result to be exactly:
1 - BX01, 2 - BxX1, 3 - Dss3, 4 - HHXY
I have this query:
DECLARE #ProID VARCHAR(8000)
SELECT #ProID = COALESCE(#ProID + ', - ', '') + Product_Id FROM TABLE
SELECT #ProID
but the return values is only :
BX01,- BxX1,- Dss3,- HHXY
The counting is missing.
How to do that?
Thanks
Assuming the numbers are the row numbers, you should be using ROW_NUMBER() (more info):
DECLARE #tmp TABLE (ID varchar(300), [Desc] varchar(300))
INSERT INTO #tmp (ID, [Desc])
SELECT 'BX01', 'Desc 1'
UNION
SELECT 'BxX1', 'Desc 2'
UNION
SELECT 'Dss3', 'Desc 3'
UNION
SELECT 'HHXY', 'Desc 4'
DECLARE #ProID VARCHAR(8000)
SELECT #ProID = COALESCE(#ProID + ', ', '') + CAST(t.row AS varchar(20))+ ' - ' + t.ID
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY ID) AS row, ID
FROM #tmp) AS t
SELECT #ProID
Try something like this using row_nu,mber function
SELECT CAST(row_number AS VARCHAR(5)) +' - '+ Product_Id +', '
from
(select Product_Id, ROW_NUMBER()OVER(order by Product_Id) as row_number
FROM TABLE ) as derived_tbl
FOR XML PATH('')

How to make row data comma separated in SQL?

I am having one query which returns me following output.
(No of results not same all time, means sometimes it gives 3 category,sometimes 8 category etc..)
CategoryName
Test1
Test2
Test3
Now i want that store procedure should return me these date in comma separated format.
e.g. output string should be like: Test1,Test2,Test3
Can you please tell me how can i achieve this?
this will work for all characters in your data:
set nocount on;
declare #YourTable table (BirthDay datetime, PersonName varchar(20))
insert into #YourTable VALUES ('1-10-2010', 'Joe' )
insert into #YourTable VALUES ('2-10-2010', 'Bob <&>' )
insert into #YourTable VALUES ('2-10-2010', 'Alice')
set nocount off
--Concatenation with FOR XML and eleminating control/encoded character expansion "& < >"
SELECT
p1.BirthDay
,STUFF(
(SELECT
', ' + p2.PersonName
FROM #YourTable p2
WHERE p2.BirthDay=p1.BirthDay
ORDER BY p2.PersonName
FOR XML PATH(''), TYPE
).value('.','varchar(max)')
,1,2, ''
) AS PersonNames
FROM #YourTable p1
GROUP BY p1.BirthDay
OUTPUT:
BirthDay PersonNames
----------------------- ------------------------
2010-01-10 00:00:00.000 Joe
2010-02-10 00:00:00.000 Alice, Bob <&>
(2 row(s) affected)
Try COALESCE or ISNULL:
DECLARE #returnValue varchar(MAX)
SELECT
#returnValue = COALESCE(#returnValue + ', ', '') + CategoryName
FROM
TableName
Have a look at something like (Full working example)
DECLARE #Table TABLE(
ID INT,
Val VARCHAR(50)
)
INSERT INTO #Table (ID,Val) SELECT 1, 'A'
INSERT INTO #Table (ID,Val) SELECT 1, 'B'
INSERT INTO #Table (ID,Val) SELECT 1, 'C'
INSERT INTO #Table (ID,Val) SELECT 2, 'B'
INSERT INTO #Table (ID,Val) SELECT 2, 'C'
--Concat
SELECT t.ID,
STUFF((
SELECT ',' + t1.Val
FROM #Table AS t1
WHERE t1.ID = t.ID
FOR XML PATH('')
), 1, 1, '')
FROM #Table t
GROUP BY t.ID
Also, you might find that Googling will provide a lot of answers.
One means:
SELECT STUFF((
SELECT ',' + CategoryName AS [text()]
FROM YourTable
FOR XML PATH('')
), 1, 1, '')
...but watch out for XML entities that will be escaped up - e.g. & => &
Just modify the KM answer in a store procedure
ALTER Procedure [dbo].[Payroll_rptAbsentReport]
#FromDate DateTime,
#ToDate DateTime,
#GFacatoryID UniqueIdentifier
As
Begin
-- Temporary table for Row data seperation
CREATE TABLE TestTable(GEmployeeGenInfoID uniqueidentifier, dtAttendDateTime varchar(max))
INSERT INTO
TestTable(GEmployeeGenInfoID, dtAttendDateTime)
SELECT
Payroll_tblAttendance.GEmployeeGenInfoID
,CONVERT(VARCHAR(max), dtAttendDateTime, 105)dtAttendDateTime
FROM Payroll_tblAttendance
INNER JOIN PIS.dbo.PIS_tblEmployeeGenInfo as EmployeeGenInfo ON Payroll_tblAttendance.GEmployeeGenInfoID= EmployeeGenInfo.GEmployeeGenInfoID
WHERE Payroll_tblAttendance.DayStatusID = 0 AND EmployeeGenInfo.GFactoryID=#GFacatoryID AND Payroll_tblAttendance.dtAttendDateTime Between #FromDate and #ToDate ORDER BY dtAttendDateTime
-- Final expected output
SELECT DISTINCT
EmployeeGenInfo.StrEmpName
,EmployeeGenInfo.StrEmpID
,Attendence.CardNo
,EmployeeDesignation.StrDesignationName
,EmployeeDept.StrDepartmentName
-- Count data will be in one column
,(Select COUNT(*) From TestTable Where GEmployeeGenInfoID=Attendence.GEmployeeGenInfoID) TotalAbsent
-- Row data set into one column seperate by coma
,substring( ( SELECT ', ' + dtAttendDateTime as [text()]
FROM TestTable
WHERE GEmployeeGenInfoID = Attendence.GEmployeeGenInfoID
FOR XML path(''), elements
), 3, 1000
) List
FROM
Payroll_tblAttendance as Attendence
INNER JOIN TestTable on TestTable.GEmployeeGenInfoID=Attendence.GEmployeeGenInfoID
INNER JOIN PIS.dbo.PIS_tblEmployeeGenInfo as EmployeeGenInfo ON Attendence.GEmployeeGenInfoID= EmployeeGenInfo.GEmployeeGenInfoID
INNER JOIN PIS.dbo.PIS_tblDesignationInfo as EmployeeDesignation ON EmployeeGenInfo.GDesignationInfoID= EmployeeDesignation.GDesignationInfoID
INNER JOIN PIS.dbo.PIS_tblDepartment as EmployeeDept ON EmployeeGenInfo.GDepartmentID= EmployeeDept.GDepartmentID
WHERE EmployeeGenInfo.GFactoryID=#GFacatoryID AND Attendence.DayStatusID = 0 AND Attendence.dtAttendDateTime Between #FromDate and #ToDate
DROP TABLE TestTable
END

Resources