What SQL query or view will show dynamic columns
You want to pivot each of your name-value pair rows in the MyTable... Try this sql:
DECLARE @Data TABLE (
DataID INT IDENTITY(1,1) PRIMARY KEY,
Data VARCHAR(MAX)
)
DECLARE @Meta TABLE (
DataID INT ,
MetaName VARCHAR(MAX),
MetaData VARCHAR(MAX)
)
INSERT INTO @Data
SELECT 'Data'
INSERT INTO @Meta
SELECT 1, 'Date', CAST(GetDate() as VARCHAR(20))
UNION
SELECT 1, 'Name', 'Joe Test'
SELECT * FROM @Data
SELECT * FROM @Meta
SELECT
D.DataID,
D.Data,
MAX(CASE MetaName WHEN 'Date' THEN MetaData ELSE NULL END) as Date,
MAX(CASE MetaName WHEN 'Name' THEN MetaData ELSE NULL END) as Name
FROM
@Meta M
JOIN @Data D ON M.DataID = D.DataID
GROUP BY
D.DataID,
D.Data
dynamic columns in Query Or view
it is not possible to create a view with a dynamic number of columns. You need to specify all the values of ColumnDataName in order for this to work.
You need to pivot your result, here is an example how you can create your view:
CREATE TABLE
xxx(SectionID int, ColumnDescription varchar(10), ColumnDataName varchar(10))
INSERT xxx values(2, 'dgj', 'column1')
INSERT xxx values(2, 'ash', 'column2')
INSERT xxx values(8, 'lkhsdh', 'column2')
go
CREATE VIEW v_xxx as
SELECT SectionId, [column1],[column2],[column3]
FROM xxx
PIVOT
(min(ColumnDescription)
FOR ColumnDataName
in([column1],[column2],[column3])
)AS p
go
SELECT * FROM v_xxx
Result:
SectionId column1 column2 column3
2 dgj ash NULL
8 NULL lkhsdh NULL
SQL: Dynamic view with column names based on column values in source table
You can perform this with a PIVOT. When doing the PIVOT you can do it one of two ways, with a Static Pivot that you will code the rows to transform or a Dynamic Pivot which will create the list of columns at run-time:
Static Pivot (See SQL Fiddle for Demo):
select id, [user], [engineer], [manu], [OS]
from
(
select t.id
, t.[user]
, p.ticketid
, p.label
, p.value
from tickets t
inner join properties p
on t.id = p.ticketid
) x
pivot
(
min(value)
for label in ([engineer], [manu], [OS])
) p
Or you can use a Dynamic Pivot (See SQL Fiddle for Demo):
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX);
select @cols = STUFF((SELECT distinct ',' + QUOTENAME(p.label)
from tickets t
inner join properties p
on t.id = p.ticketid
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT id, [user], ' + @cols + ' from
(
select t.id
, t.[user]
, p.ticketid
, p.label
, p.value
from tickets t
inner join properties p
on t.id = p.ticketid
) x
pivot
(
min(value)
for label in (' + @cols + ')
) p '
execute(@query)
Both query will return the same results.
View with dynamic columns In SQL Server
This is not possible with a view because SQL Server queries are always statically typed in the sense that both column count, names and types are statically known at execution time.
You need dynamic SQL for dynamic columns.
Views do not support dynamic SQL. You have to find some other way of returning the data, maybe with one row per logical column.
SQL Server select query dynamic column output
Provided the WEEK numbers and Order numbers are consistent, it is a small matter to maintain the column sequence.
You may notice I used #forecast and #article because I did not know your actual table names.
Example
Declare @SQL varchar(max) = '
Select *
From (
Select A.ArticleID
,D.Description
,B.*
From #forecast A
Join #article D on A.ArticleID=D.ArticleID
Cross Apply (values (''Week''+left(Week,4),Amount) ) B(Item,Value)
) A
Pivot (max([Value])
For [Item] in (' + Stuff((Select ','+QuoteName('Week'+left(Week,4))
From (Select Distinct top 100 [Order],Week From #forecast Order by [Order] ) A
For XML Path('')),1,1,'') + ') ) p'
Exec(@SQL);
--Print @SQL
Returns
ArticleID Description Week51 Week52 Week1 Week2 Week3
1 Test 0 150 0 200 0
SQL Query to compare dynamic column headers with another static tables columns
You certainly could use sys.columns
to return your static columns from Table2 and compare them to the dynamic columns in Table1 and use UNPIVOT
on a select of your first row.
I have found that it was far easier to wrap this all in a T-SQL block and insert to two lists into temp tables before comparing due to data type conflicts (probably be solved by using CAST)
BEGIN
DECLARE @table1 TABLE (colname VARCHAR(MAX))
DECLARE @table2 TABLE (colname VARCHAR(MAX))
INSERT INTO @table1 SELECT COLNAME FROM (SELECT a, b, c FROM TABLE1 WHERE...first row condition) a UNPIVOT (COLNAME FOR COLS IN ([a],[b],[c])) a
INSERT INTO @table2 SELECT CAST (name AS NVARCHAR(100)) name FROM sys.columns WHERE object_id = OBJECT_ID('TABLE2')
SELECT a.colname cols1, b.colname cols2
FROM @table2 a
FULL OUTER JOIN @table1 b ON (a.colname = b.colname)
END
You can easily change the final select to return what you want
Dynamically selecting the column to select from the row itself in SQL
You just need a CASE
expression...
SELECT
id,
SelectedP,
CASE SelectedP
WHEN 'P1' THEN P1
WHEN 'P2' THEN P2
WHEN 'P3' THEN P3
WHEN 'P4' THEN P4
WHEN 'P5' THEN P5
END
AS SelectedPValue
FROM
yourTable
This will return NULL
for anything not mentioned in the CASE
expression.
EDIT:
An option with just a little less typing...
SELECT
id, SelectedP, val
FROM
yourTable AS pvt
UNPIVOT
(
val FOR P IN
(
P1,
P2,
P3,
P4,
P5
)
)
AS unpvt
WHERE
SelectedP = P
NOTE: If the value of SelectedP
doesn't exist in the UNPIVOT
, then the row will not appear at all (unlike the CASE
expression which will return a NULL
)
Demo: https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=b693738aac0b594cf37410ee5cb15cf5
EDIT 2:
I don't know if this will perform much worse than the 2nd option, but this preserves the NULL
behaviour.
(The preferred option is still to fix your data-structure.)
SELECT
id, SelectedP, MAX(CASE WHEN SelectedP = P THEN val END) AS val
FROM
yourTable AS pvt
UNPIVOT
(
val FOR P IN
(
P1,
P2,
P3,
P4,
P5
)
)
AS unpvt
GROUP BY
id, SelectedP
Demo : https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=f3f64d2fb6e11fd24d1addbe1e50f020
Aggregate dynamic columns in SQL Server
When writing Dynamic Query, you start off with a non-dynamic query. Make sure you gets the result of the query is correct before you convert to dynamic query.
For the result that you required, the query will be
with cte as
(
select it.Unique_Key, ot.System_Name
from data it
left join data ot on it.Unique_Key = ot.Unique_Key
and ot.System_Name <> 'IT'
where it.System_Name = 'IT'
)
select [ITKey] = count(distinct Unique_Key),
[ACCOUNTS] = count(case when System_Name = 'ACCOUNTS' then Unique_Key end) * 100.0
/ count(distinct Unique_Key),
[HR] = count(case when System_Name = 'HR' then Unique_Key end) * 100.0
/ count(distinct Unique_Key),
[PAYROLL] = count(case when System_Name = 'PAYROLL' then Unique_Key end) * 100.0
/ count(distinct Unique_Key)
from cte;
Once you get the result correct, it is not that difficult to convert to dynamic query. Use string_agg() or for xml path for those repeated rows
declare @sql nvarchar(max);
; with cte as
(
select distinct System_Name
from data
where System_Name <> 'IT'
)
select @sql = string_agg(sql1 + ' / ' + sql2, ',' + char(13))
from cte
cross apply
(
select sql1 = char(9) + quotename(System_Name) + ' = '
+ 'count(case when System_Name = ''' + System_Name + ''' then Unique_Key end) * 100.0 ',
sql2 = 'count(distinct Unique_Key)'
) a
select @sql = 'with cte as' + char(13)
+ '(' + char(13)
+ ' select it.Unique_Key, ot.System_Name' + char(13)
+ ' from data it' + char(13)
+ ' left join data ot on it.Unique_Key = ot.Unique_Key' + char(13)
+ ' and ot.System_Name <> ''IT''' + char(13)
+ ' where it.System_Name = ''IT''' + char(13)
+ ')' + char(13)
+ 'select [ITKey] = count(distinct Unique_Key), ' + char(13)
+ @sql + char(13)
+ 'from cte;' + char(13)
print @sql;
exec sp_executesql @sql;
db<>fiddle demo
Related Topics
Creating Trigger That Runs on Two Tables
Sql How to Remove Duplicates Within Select Query
Generate Create Scripts for a List of Indexes
"Pivoting" a Table in SQL (I.E. Cross Tabulation/Crosstabulation)
Best Way to Find SQL Locks in SQL Server 2008
Trying to Connect to an Odbc Server Using Rodbc in Ubuntu
Sql Server 2000 - Query a Table's Foreign Key Relationships
How to Concat Multiple Rows into One Column in SQL Server
Sql 2005 How to Use Keyword Like in a Case Statement
Order by a Field Being Equal to a Specific Value
Select All Projects That Have Matching Tags
Why Google's Bigtable Referred as a Nosql Database
Is It Faster to Check If Length = 0 Than to Compare It to an Empty String
How to Insert N Rows of Default Values into a Table
Sql Sum by Year Report, Looking for an Elegant Solution