How to dynamically convert rows to columns in SQL Server - sql

I want to convert rows to columns dynamically, for sample data I have given below query.
create table testtable
(
tableid int primary key identity(1,1),
tableDatetime datetime,
names varchar(50),
tablevalue decimal(18,9)
)
go
insert into testtable
select '2019-06-13 13:56:39.117', 'test1',23.45 union all
select '2019-06-13 13:56:39.117', 'test2',33.45 union all
select '2019-06-13 13:56:39.117', 'test3',10.45 union all
select '2019-06-13 13:56:39.117', 'test4',90.45 union all
select '2019-06-13 14:01:41.280', 'test1',33.45 union all
select '2019-06-13 14:01:41.280', 'test2',53.45 union all
select '2019-06-13 14:01:41.280', 'test3',41.45 union all
select '2019-06-13 14:01:41.280', 'test4',93.45 union all
select '2019-06-13 14:06:42.363', 'test1',30.45 union all
select '2019-06-13 14:06:42.363', 'test2',13.45 union all
select '2019-06-13 14:06:42.363', 'test3',23.45 union all
select '2019-06-13 14:06:42.363', 'test4',73.45
go
select * from testtable
I want to convert data in attached image format
Thanks,

You may try dynamic sql query as per your table structure.
GO
declare #query varchar(max)
set #query = (select stuff( (select distinct ',' + names from testtable for xml path ('')) ,1,1,'') as d)
declare #resquery nvarchar(max)
set #resquery = '
select * from (
select tableDatetime , names , tablevalue from testtable
) as d
pivot ( max(tablevalue) for names in ( ' + #query + ' ) ) as pv'
exec sp_executesql #resquery
GO
Please use this as per your table structure, this will create dynamic column names for your current table data. Which is further use in pivot to convert your rows into columns.
Mark it as accepted, or comment for further query.

Related

How to write vertical columns [duplicate]

This question already has answers here:
Understanding PIVOT function in T-SQL
(7 answers)
Closed 3 years ago.
How can I write a vertical table horizontally with sql
  I want to make the following table like the example in the second picture
example
ı want to write
Try this
DECLARE #Sql nvarchar(max),
#DynamicColumn nvarchar(max),
#MaxDynamicColumn nvarchar(max)
SELECT #DynamicColumn = STUFF((SELECT DISTINCT', '+QUOTENAME(CAST(Col1 AS VARCHAR(50)))
FROM #Temp FOR XML PATH ('')),1,1,'')
SELECT #DynamicColumn
SET #Sql='SELECT '+ #DynamicColumn+'
FROM
(
SELECT *
FROM #Temp o
)AS src
PIVOT
(
MAX(Col2) FOR [Col1] IN ('+#DynamicColumn+')
) AS Pvt
'
EXEC (#Sql)
PRINT #Sql
Hi if understand your query i think this query can help you to get excepted result :
CREATE TABLE #TEMP (colName varchar(250), colOther varchar(250))
INSERT INTO #TEMP
SELECT 'Desen', '2908A' UNION ALL
SELECT 'Desen', '2908A' UNION ALL
SELECT 'Desen', '2908A' UNION ALL
SELECT 'Desen', '2908A' UNION ALL
SELECT 'Ebat', '125x200 R' UNION ALL
SELECT 'Ebat', '125x200 R' UNION ALL
SELECT 'Ebat', '125x200 R' UNION ALL
SELECT 'Ebat', '125x200 R' UNION ALL
SELECT 'ZeminRengi', 'KEMIK' UNION ALL
SELECT 'ZeminRengi', 'KEMIK' UNION ALL
SELECT 'ZeminRengi', 'KEMIK' UNION ALL
SELECT 'ZeminRengi', 'KEMIK'
select Desen,Ebat,ZeminRengi
from #TEMP
PIVOT (
MAX(colOther)
FOR colName IN (Desen,Ebat,ZeminRengi)) AS Pvt
DROP TABLE #TEMP
See different link and google :
Understanding PIVOT function in T-SQL
MSDN
Google- search

Pivot table from horizontal to vertical

i have a following table of results:
What i want is a resulted table with following structure:
Is any posibility to do that with SQL?
Thanks in advance.
EDIT (SQL query with exampled temp table):
CREATE TABLE #FINAL_STACK
(
FB_DATE datetime,
FB_DESC VARCHAR(200)
)
INSERT INTO #FINAL_STACK(FB_DATE, FB_DESC)
SELECT '2017-03-09', 'D - FIZ: 1'
UNION
SELECT '2017-03-09', 'D - PRI: 1'
UNION
SELECT '2017-03-10', 'D - FIZ: 1'
UNION
SELECT '2017-03-10', 'D - PRI: 1'
UNION
SELECT '2017-03-13', 'D - FIZ: 2'
UNION
SELECT '2017-03-13', 'D - PRI: 1'
UNION
SELECT '2017-03-13', 'D - TEPAP: 1'
SELECT * FROM #FINAL_STACK
Try this:
DECLARE #DynammicTSQLStatement NVARCHAR(MAX)
,#DynamicPIVOTColumns NVARCHAR(MAX);
SET #DynamicPIVOTColumns = STUFF
(
(
SELECT ',[' + CAST([FB_DATE] AS VARCHAR(12)) + ']'
FROM #FINAL_STACK
GROUP BY [FB_DATE]
ORDER BY [FB_DATE]
FOR XML PATH('') ,TYPE
).value('.', 'NVARCHAR(MAX)')
,1
,1
,''
);
SET #DynammicTSQLStatement = N'
SELECT *
FROM
(
SELECT *
,ROW_NUMBER() OVER (PARTITION BY FB_DATE ORDER BY (SELECT 1)) AS RID
FROM #FINAL_STACK
) DS
PIVOT
(
MAX([FB_DESC]) FOR [FB_DATE] IN (' + #DynamicPIVOTColumns + ')
) PVT';
EXEC sp_executesql #DynammicTSQLStatement;
We need to perform dynamic pivot in order to be sure it will always work for different days. Also, note we are creating a row ID column using ROW_NUMBER in order to ensure all records for particular date are displayed. Otherwise, you will get only one value (for example the min or the max) depending on the PIVOT aggregate function.

MsSql "group by" result table design

How to convert Result 1 to result 2. I can not get result2 using the pivot table.
Result1
Result1 QUERY
SELECT Country,City,Count(*) as "Count"
FROM Customers
GROUP BY Country,City
Result2
There is no such feature of SQL other that PIVOT where, as you have discovered, you need to know the values up front.
This formatting is typically done in the output part of the system, such as your report engine. SSRS for example can handle this nicely & out of the box.
You would need dynamic SQL to achieve this lower down in the stack.
Try this dynamic sql
IF OBJECT_ID('tempdb..#Temp') IS NOT NULL
DROP TABLE #Temp
CREATE TABLE #Temp([Country] VARCHAR(20),[City] VARCHAR(20),[Count] INT)
INSERT INTO #Temp
SELECT 'Germany' ,'Aachen' ,1 UNION ALL
SELECT 'USA' ,'Albuquerque',1 UNION ALL
SELECT 'USA' ,'Anchorage' ,1 UNION ALL
SELECT 'Denmark' ,'Arhus' ,1 UNION ALL
SELECT 'Spain' ,'Barcelone' ,1
DECLARE #Colmn nvarchar(max),
#Sql nvarchar(max)
SELECT #Colmn=STUFF((SELECT distinct ', '+QUOTENAME([Country]) FROM #Temp
FOR XML PATH ('')),1,1,'')
SET #Sql =' SELECT Cityynames ,'+ #Colmn +' FROM
(
SELECT *,Country AS Countrynames,City AS Cityynames
FROM #Temp
)dt
PIVOT
(
MAX([Count]) FOR [Country] IN ('+#Colmn+')
) AS Pvt'
PRINT #Sql
EXEC (#Sql)

How to retrieve data from multiple daily tables in SQL Server

I am new to Microsoft SQL Server 2008. I need some help in retrieving data from multiple tables which have same columns with same datatype.
Currently I have multiple tables in my database, each table contains data for a single day. For example, I have the following tables:
Table_20160820
Table_20160821
Table_20160822
Table_20160823
Table_20160824
Table_20160825
All the tables have same columns with same datatype say:
column_1
column_2
column_3
column_4
Now, is it possible to retrieve the columns from all the tables using a single query.
What I am exactly looking for is to get the count of column_3 which will be grouped by column_1 for all the tables. I want to avoid writing multiple queries as I need to fetch the data for an entire month i.e. from 30 tables.
As the comments have said, it'd be best to organize this into a single table, and then add a date column so you can see when each row was added. You can even set the default value of the date_created column to be getdate().
To get all of the data together use the UNION Operator in conjunction with an insert statement to your new better table.
CREATE TABLE Better_Table (Column_1 <type>, Column_2 <type>, ..., Date_Created DateTime2(7) Default GETDATE())
GO
INSERT INTO Better_Table (Column_1, Column_2, ...)
SELECT *, '2016/08/22' FROM Table_20160822
UNION
SELECT *, '2016/08/23' FROM Table_20160823
...
Once you've done this your query will be far simpler:
SELECT Column_1, COUNT(Column_3)
FROM Better_Table
WHERE date_created >= '2016/08/01'
AND date_created < '2016/09/01'
GROUP BY Column_1
Although you can still do this in the db current state by using the union operator in the group by query. It would look something like this:
SELECT a.column_1, COUNT(a.column_3)
FROM (
SELECT column_1, Column_3
FROM Table_20160822
UNION ALL
SELECT column_1, Column_3
FROM Table_20160823
) a
GROUP BY a.Column_1
Just expand this to the tables you need to grab from.
You can use CTE to get all dates you need, then create a query and execute it:
DECLARE #dateStart datetime = '2016-08-01',
#dateFinish datetime = '2016-09-01',
#query nvarchar(max)
;WITH cte as (
SELECT #dateStart as d
UNION ALL
SELECT DATEADD(day,1,d)
FROM cte
WHERE DATEADD(day,1,d) < #dateFinish
)
SELECT #query = (
SELECT 'SELECT column_1, COUNT(column_3) FROM ( '
+ STUFF((
SELECT ' UNION ALL SELECT * FROM [Table_'+CONVERT(nvarchar(8),d,112)+'] '
FROM cte
FOR XML PATH('')
),1,10,'') + ') as t GROUP BY column_1 '
FOR XML PATH('')
)
PRINT #query
EXEC sp_executesql #query
Output of #query variable:
SELECT column_1, COUNT(column_3)
FROM (
SELECT * FROM [Table_20160801] UNION ALL
SELECT * FROM [Table_20160802] UNION ALL
SELECT * FROM [Table_20160803] UNION ALL
SELECT * FROM [Table_20160804] UNION ALL
....
SELECT * FROM [Table_20160831]
) as t
GROUP BY column_1
As mentioned above this is a bad design and it would be good if the design is fixed at first place. This is a technical debt which has to be paid back sooner or later. Anyway here's how you can do it:
DECLARE #dtStartDate DATE,
#dtEndDate DATE,
#nvchTablePrefix NVARCHAR(50),
#nvchQuery NVARCHAR(max)
SELECT #dtStartDate = '20160801',
#dtEndDate = '20160831',
#nvchTablePrefix = 'Table_'
CREATE TABLE #temp
(name NVARCHAR(100))
WHILE(#dtStartDate <= #dtEndDate)
BEGIN
INSERT INTO #temp
SELECT ' SELECT column_1, column_3 FROM ' + #nvchTablePrefix + CONVERT(NVARCHAR,#dtStartDate,112)
SELECT #dtStartDate = DATEADD(d,1,#dtStartDate)
IF (#dtStartDate <= #dtEndDate)
INSERT INTO #temp
SELECT ' UNION '
END
SELECT #nvchQuery = 'SELECT column_1, COUNT(column_3) as column3count FROM ( '
SELECT #nvchQuery = #nvchQuery + name FROM #temp
SELECT #nvchQuery = #nvchQuery + ') t GROUP BY column1'
PRINT #nvchQuery
EXEC sp_executesql #nvchQuery
DROP TABLE #temp
OUTPUT of print statement will be like -
SELECT column_1, COUNT(column_3) as column3count
FROM
( SELECT column_1, column_3 FROM Table_20160801
UNION
SELECT column_1, column_3 FROM Table_20160802
UNION
....
UNION
SELECT column_1, column_3 FROM Table_20160831
) t GROUP BY column1

SQL query problem

Let´s say I have two tables, "Garden" and "Flowers". There is a 1:n-relationship between these tables, because in a garden can be many flowers. Is it possible to write an SQL query which returns a result with the following structure:
GardenName Flower1Name Flower2Name .... (as long as there are entries in flowers)
myGarden rose tulip
CREATE TABLE #Garden (Id INT, Name VARCHAR(20))
INSERT INTO #Garden
SELECT 1, 'myGarden' UNION ALL
SELECT 2, 'yourGarden'
CREATE TABLE #Flowers (GardenId INT, Flower VARCHAR(20))
INSERT INTO #Flowers
SELECT 1, 'rose' UNION ALL
SELECT 1, 'tulip' UNION ALL
SELECT 2, 'thistle'
DECLARE #ColList nvarchar(max)
SELECT #ColList = ISNULL(#ColList + ',','') + QUOTENAME('Flower' + CAST(ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS VARCHAR))
FROM #Flowers WHERE GardenId = (
SELECT TOP 1 GardenId
FROM #Flowers
ORDER BY COUNT(*) OVER (PARTITION BY GardenId) DESC
)
EXEC (N'
;WITH cte As
(
SELECT *, ''Flower'' + CAST(ROW_NUMBER() OVER (PARTITION BY GardenId ORDER BY (SELECT 0)) AS VARCHAR) RN
FROM #Flowers F
)
SELECT Name,' + #ColList + N'
FROM cte
JOIN #Garden g ON g.Id = GardenId
PIVOT (MAX(Flower) FOR RN IN (' + #ColList + N')) Pvt')
DROP TABLE #Garden
DROP TABLE #Flowers
Returns
Name Flower1 Flower2
-------------------- -------------------- --------------------
myGarden rose tulip
yourGarden thistle NULL
Look at using Pivot in SQL Server. Here is a good link that goes over how it works:
http://www.kodyaz.com/articles/t-sql-pivot-tables-in-sql-server-tutorial-with-examples.aspx
Ok, i think i got it working. Try this:
with temp as
(
select 'myGarden' as name, 'test1' as flower
union
select 'myGarden','test2'
union
select 'myGarden','test5'
union
select 'abeGarden','test4'
union
select 'abeGarden','test5'
union
select 'martinGarden', 'test2'
)
select* from temp
pivot
(
max(flower)
for flower in (test1,test2,test3,test4,test5)
) PivotTable
You could also make the values in the in clause dynamic. Since this is a CTE i can't in my example.
Dynamic SQL with a cursor is the only way I can think of, and it won't be pretty.
If you only want the results for one garden at a time this would give you the data:
select gardenName from tblGarden where gardenid = 1
Union ALL
select tblFLowers.flowerName from tblFlowers where gardenid = 1