Is there an easy way to select from a (long) array?
I want something like this
SELECT citizenship, count(1)
FROM table
WHERE year(date) = 2018
GROUP BY citizenship
But I want all citizenship as column and all dates (from 2000 until as 2018) as rows so I can delete the where clause.
Sounds like you want to use PIVOT columns.
Heres what I think you want... ( in SQL Server)
See this article: https://www.databasejournal.com/features/mssql/converting-rows-to-columns-pivot-and-columns-to-rows-unpivot-in-sql-server.html
Applied to you that could be...
--Declare necessary variables
DECLARE #SQLQuery AS NVARCHAR(MAX)
DECLARE #PivotColumns AS NVARCHAR(MAX)
--Get unique values of pivot column
SELECT #PivotColumns= COALESCE(#PivotColumns + ',','') + QUOTENAME([citizenship])
FROM (SELECT DISTINCT [citizenship] FROM [dbo].[table]) AS PivotExample
--Create the dynamic query with all the values for
--pivot column at runtime
SET #SQLQuery =
N'SELECT [Year], ' + #PivotColumns + '
FROM (SELECT [citizenship], YEAR([Date]) AS [Year], COUNT(1) As Counter
FROM [Table] GROUP BY [citizenship], YEAR([Date])) AS A
PIVOT( SUM(Counter)
FOR [citizenship] IN (' + #PivotColumns + ')) AS P'
SELECT #SQLQuery
--Execute dynamic query
EXEC sp_executesql #SQLQuery
Adding distinct will give you list of unique citizens
SELECT distinct citizenship
FROM table
WHERE year(date) >= 2000 and year(date) <= 2018
Related
I am trying to build a dynamic query and create a ranking base on one of the columns
this is the code I have so far
/*Declare Variable*/
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX),
#PivotColumnNames AS NVARCHAR(MAX),
#PivotSelectColumnNames AS NVARCHAR(MAX),
#Week_Value AS NVARCHAR(MAX),
#Rank AS NVARCHAR(MAX)
--Get distinct values of the PIVOT Column
SELECT #PivotColumnNames= ISNULL(#PivotColumnNames + ',','')+ QUOTENAME([W])
FROM (SELECT DISTINCT [W] FROM [Server].[dbo].[Table]) AS cat
ORDER BY [W]
--Get distinct values of the PIVOT Column with isnull
SELECT #PivotSelectColumnNames = ISNULL(#PivotSelectColumnNames + ',','')+ 'ISNULL(' + QUOTENAME([W]) + ', 0) AS '+ QUOTENAME([W])
FROM (SELECT DISTINCT [W] FROM [Server].[dbo].[Table]) AS cat
ORDER BY [W]
--Get current week value
SET #Week_Value = SUBSTRING(#PivotColumnNames,81,15)
--PRINT #Week_Value --Make sure value is correct
--Get the ranking for previews week
SET #Rank = 0 -- this initialize the rank
--Prepare the PIVOT query using the dynamic
SET #DynamicPivotQuery = '
SELECT TOP 200 [L], [Doc_ID], '+#PivotSelectColumnNames+','+#Rank+' AS RNK
FROM
(SELECT [L],
[Doc_ID],
[W],
ISNULL(CAST([PV] AS INT),0) AS [Page_Views]
FROM [Server].[dbo].[Table]
WHERE LEN([Doc_ID]) = 8 OR LEN([Doc_ID]) = 9)Tab1
PIVOT
(
SUM([Page_Views])
FOR [Week] IN ('+#PivotColumnNames+')
) AS Tab2
ORDER BY '+#Week_Value+' DESC'
--Execute the Dynamic Pivot Query
EXEC sp_executesql #DynamicPivotQuery
so the problem is that the rank is static and I can't figure out how to sum +1 in each row, the rank has to be set base on #PivotColumnNames order, this is a sample from the data I have so far applying the code above
L
Doc_ID
Week 12, 2021
Week 13, 2021
Week 14, 2021
Week 15, 2021
RNK
en
c03722645m
191867
168145
188472
185189
0
fr
c03746609
55908
53467
56678
56028
0
this is what I would like
L
Doc_ID
Week 12, 2021
Week 13, 2021
Week 14, 2021
Week 15, 2021
RNK
en
c03722645m
191867
168145
188472
185189
1
fr
c03746609
55908
53467
56678
56028
2
any help or recommendation would be appreciated
Hi There are multiple Ranking options available in TSQL. The question that you have you have to determine the required ranking function as per your requirement. I will use RANK() function in this periocular solution
/*Declare Variable*/
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX),
#PivotColumnNames AS NVARCHAR(MAX),
#PivotSelectColumnNames AS NVARCHAR(MAX),
#RankingSelectColumn AS VARCHAR(MAX), --Create ranking statement (Added)
#Week_Value AS NVARCHAR(MAX),
#Rank AS NVARCHAR(MAX)
--Get distinct values of the PIVOT Column
SELECT #PivotColumnNames= ISNULL(#PivotColumnNames + ',','')+ QUOTENAME([W])
FROM (SELECT DISTINCT [W] FROM [Server].[dbo].[Table]) AS cat
ORDER BY [W]
--Make Ranking logic depending on the rank change ASC or DESC
SELECT #RankingSelectColumn = ISNULL(#RankingSelectColumn + ' ASC,','')+ 'ISNULL(' + QUOTENAME([W]) + ', 0) AS '+ QUOTENAME([W])
FROM (SELECT DISTINCT [W] FROM [Server].[dbo].[Table]) AS cat
ORDER BY [W]
--Get distinct values of the PIVOT Column with isnull (Added)
SELECT #PivotSelectColumnNames = ISNULL(#PivotSelectColumnNames + ',','')+ 'ISNULL(' + QUOTENAME([W]) + ', 0) AS '+ QUOTENAME([W])
FROM (SELECT DISTINCT [W] FROM [Server].[dbo].[Table]) AS cat
ORDER BY [W]
--Get current week value
SET #Week_Value = SUBSTRING(#PivotColumnNames,81,15)
--PRINT #Week_Value --Make sure value is correct
--Get the ranking for previews week
SET #Rank = 0 -- this initialize the rank
--Prepare the PIVOT query using the dynamic (Added Rank function)
SET #DynamicPivotQuery = '
SELECT TOP 200 [L], [Doc_ID], '+#PivotSelectColumnNames+',RANK() OVER('+#RankingSelectColumn+') AS RNK
FROM
(SELECT [L],
[Doc_ID],
[W],
ISNULL(CAST([PV] AS INT),0) AS [Page_Views]
FROM [Server].[dbo].[Table]
WHERE LEN([Doc_ID]) = 8 OR LEN([Doc_ID]) = 9)Tab1
PIVOT
(
SUM([Page_Views])
FOR [Week] IN ('+#PivotColumnNames+')
) AS Tab2
ORDER BY '+#Week_Value+' DESC'
--Execute the Dynamic Pivot Query
EXEC sp_executesql #DynamicPivotQuery
This will rank according to the column logic
I have a table like this with 145.695 rows.
SERVER
TAPE
ACS08
M00030L3
ACS08
M00253L3
ACS09
M00580L3
ACS09
M00602L3
ACS10
M00580L4
ACS10
M00602L5
ACS10
M00602L7
Now I want to reach a target table structure like this:
ACS08
ACS09
ACS10
M00030L3
M00580L3
M00580L4
M00253L3
M00602L3
M00602L5
M00602L7
I need help because I dont know how can I do.
You can use dynamic pivot to get the desired results.
First we need to generate the dynamic columns based on the [SERVER] column values and then pivot the values as per the requirement:
DECLARE #cols NVARCHAR(MAX), #query NVARCHAR(MAX);
SET #cols = STUFF((SELECT DISTINCT ','+ QUOTENAME([SERVER])
FROM T FOR XML PATH(''), TYPE
).value('.', 'nvarchar(max)'), 1, 1, ''); --XML way of getting the column values
SET #query = 'SELECT '+#cols+' from
(
SELECT [SERVER], [TAPE], ROW_NUMBER() OVER (PARTITION BY [SERVER] ORDER BY (SELECT NULL)) as RN --We need to add a unique number to select all rows while doing aggregation for the PIVOT
FROM T
)x
PIVOT (max([TAPE]) for [SERVER] in ('+#cols+')
) PVT';
EXECUTE (#query);
Please find the db<>fiddle here.
Try this:
DECLARE #Columns nvarchar(max), #Sql nvarchar(max);
SELECT
#Columns =
STRING_AGG(
'MAX(CASE [Server] WHEN ' + QUOTENAME([Server], '''') + ' THEN [Tape] END) AS ' + QUOTENAME([Server]),
','
) WITHIN GROUP(ORDER BY [Server])
FROM
(
SELECT [Server] FROM T GROUP BY [Server]
) S;
SET #Sql =
'SELECT ' + #Columns + ' FROM
(SELECT [Server], [Tape], ROW_NUMBER() OVER (PARTITION BY [SERVER] ORDER BY [Server]) as RN FROM T) S
GROUP BY RN'
EXEC(#Sql);
Note: STRING_AGG() is supported on SQL Server 2017 and later.
I am querying SQL Server where I have multiple columns with sum aggregation. I'm wondering if there is a way to keep column name after doing sum over each of them.
I want to avoid using aliases immediately after the selected column as their numbers and names change over time.
Example of my result:
My query:
DECLARE #SQLQUERY AS NVARCHAR(MAX)
DECLARE #PivotColumns AS NVARCHAR(MAX)
DECLARE #SumColumns as NVARCHAR(MAX)
SELECT #PivotColumns = COALESCE(#PivotColumns + ',','') + QUOTENAME(description)
FROM [example-base].dbo.table
SELECT #SumColumns = 'sum('+Replace(#PivotColumns,',','),sum(')+')'
SET #SQLQUERY = N'SELECT TOP(100) Weeks, Years, Code,'+#SumColumns+ '
FROM [example-base].dbo.table
group by Weeks,Years,Code'
EXECUTE sp_executesql #SQLQUERY
Is there a way to keep column name on which is done sum?
Be aware of the potential performance issues by building a query with text. Moreover, your result may be not predictable while the number of columns can evolve between two executions.
To add an alias to your columns, you may use this statement :
DECLARE #SumColumns AS nvarchar(MAX);
SELECT #SumColumns = CONCAT(COALESCE(#PivotColumns + ',', ''), 'SUM(', QUOTENAME(description), ') AS ', QUOTENAME(description))
FROM [example-base].dbo.table
...a union..?
SET #SQLQUERY = N'
SELECT TOP(0) Weeks, Years, Code,'+#PivotColumns+ '
FROM [example-base].dbo.table
UNION ALL
SELECT TOP(100) Weeks, Years, Code,'+#SumColumns+ '
FROM [example-base].dbo.table
group by Weeks,Years,Code'
I have a dynamic SQL Query that is providing the correct data but I have extra rows appearing, I'm not sure why. Query is this
-- Nuke the temp DB if it already exists
IF OBJECT_ID('tempdb..##TBL_TEMP') IS NOT NULL
DROP TABLE ##TBL_TEMP
--Parameter to hold dynamically created SQL Script
declare #sqlquery as nvarchar(max)
--Parameter to hold the Pivoted Column Values
declare #pivotcolumns as nvarchar(max)
--generate list of territories that will become column names
select #pivotcolumns = coalesce(#pivotcolumns + ',','') + quotename(Territory)
from
(SELECT DISTINCT TERRITORY FROM LiveGAPDetailedBudget
where res_id = '160') AS X
--select #pivotcolumns
--create dynamic query with all values for pivot at runtime
set #sqlquery = 'SELECT [ProductCategory] AS "Product Category",' + #pivotcolumns +' INTO ##TBL_TEMP
FROM LiveGAPDetailedBudget
PIVOT (MAX([Budget])
FOR [Territory] IN (' + #pivotcolumns +')) AS T WHERE res_id = 160'
--select #sqlquery
--Execute Dynamic Query
EXEC sp_executesql #sqlquery
--View results in temp table
SELECT * FROM ##TBL_TEMP order by [Product Category]
The output from the query is linked - I can't for the life of me get these rows consolidated to eliminate nulls....see link below
You are selecting extra columns that you are not required for pivoting.
change your query to
set #sqlquery = 'SELECT [ProductCategory] AS "Product Category",'
+ #pivotcolumns
+ ' INTO ##TBL_TEMP
FROM (
SELECT [ProductCategory], [Territory], [Budget]
FROM LiveGAPDetailedBudget
WHERE res_id = 160
) AS D
PIVOT (MAX([Budget])
FOR [Territory] IN (' + #pivotcolumns +')) AS T '
I need to use pivot to create time table from the following data:
I'm using this query
select
start_time, end_time, s.subj_name, tt.dd
from
time_table tt
inner join
subj s on tt.subjid = s.subjid
I am able to pivot my result to
I used following SQL code to do that:
--Declare necessary variables
DECLARE #SQLQuery AS NVARCHAR(MAX)
DECLARE #PivotColumns AS NVARCHAR(MAX)
--Get unique values of pivot column
SELECT #PivotColumns = COALESCE(#PivotColumns + ',','') + QUOTENAME(dd)
FROM (SELECT DISTINCT(dd)
FROM time_table tt
WHERE divid = 1 AND tt.active = 1) AS PivotExample
SELECT #PivotColumns
--Create the dynamic query with all the values for
--pivot column at runtime
SET #SQLQuery =
N'SELECT start_time,end_time, ' + #PivotColumns + '
FROM [dbo].[time_table]
PIVOT( SUM(subjid)
FOR dd IN (' + #PivotColumns + ')) AS P'
SELECT #SQLQuery
--Execute dynamic query
EXEC sp_executesql #SQLQuery
Do help me out to get subjectname as value instead of subjectid
Since you are pivoting a VARCHAR, you can't use SUM, but have to use MAX or MIN
Try instead:
SET #SQLQuery =
N'SELECT start_time,end_time, ' + #PivotColumns + '
FROM [dbo].[time_table]
PIVOT( MAX(subjectname)
FOR dd IN (' + #PivotColumns + ')) AS P'
Found answer for it which provides simpler way to get it.
click to get answer