I'm developing a program where I have multiple columns which I need to show the sum of to anEnd-user. These columns are assigned in the table ColumnTest in the column ColumnNames and their names can be changed by the user. Therefore I need to look up all the column names in ColumnTest\ColumnNames and afterwards sum all values regarding these columnnames from the outputtable.
I have previously used this script where I get all the columnnames in #cols like this [col1].[col2].[col3] and so on, but when I try to run the query I'm not able to sum these columns using '+ #cols + '. When I run this I get the following error: The SUM function requires 1 argument(s). Is there a viable option to do this procedure, without compromising the loading-time substantially?
DECLARE
#cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SELECT #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.ColumnNames)
FROM ColumnTest c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)') ,1,1,'')
set #query =
'
SELECT
ID
,SUM('+ #cols + ')
FROM Output_table
GROUP BY
ID
'
execute(#query);
Try this,
DECLARE
#cols AS NVARCHAR(MAX)='',
#query AS NVARCHAR(MAX);
SELECT #cols += 'SUM('+ColumnNames+') as ['+ColumnNames+'],'
from
(
SELECT distinct ColumnNames FROM ColumnTest
)A
SELECT #cols=LEFT(#cols,LEN(#cols)-1)
set #query =
'
SELECT ID,'+ #cols + '
FROM Output_table
GROUP BY ID
'
execute(#query);
or if you want addition of all column values you can use below query
DECLARE #cols AS NVARCHAR(MAX)='',
#query AS NVARCHAR(MAX);
SELECT #cols += ''+ColumnNames+'+'
FROM
(
SELECT DISTINCT ColumnNames FROM ColumnTest
)A
SELECT #cols=LEFT(#cols,LEN(#cols)-1)
set #query =
'
SELECT ID,SUM('+ #cols + ')
FROM Output_table
GROUP BY ID
'
execute(#query);
You can not use comma separated like ','
You can use '+'
Try this
DECLARE
#cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SELECT #cols = STUFF((SELECT distinct '+' + QUOTENAME(c.ColumnNames)
FROM ColumnTest c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)') ,1,1,'')
set #query =
'
SELECT
ID
,SUM('+ #cols + ')
FROM Output_table
GROUP BY
ID
'
execute(#query);
Related
I want to declare a table variable and fill it from the pivot with dynamic column to perform join statement.
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX)
SELECT #cols =
STUFF((SELECT DISTINCT ',' + QUOTENAME(ColName)
FROM [sbs].[ProposalAmounts]
GROUP BY ColName, ProposalID
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
SET #query = N'SELECT ProposalID, ' + #cols + N' from
(select ProposalID, Amount, ColName from [sbs].[ProposalAmounts]) x
PIVOT
(MAX(Amount)for ColName in (' + #cols + N')) p '
EXEC sp_executesql #query;
This is what I've done so far and I'm confused as to how to declare a table variable that has dynamic columns in it.
This is the result of the query above:
And this is the result of the table I want to perform join statement:
Like Jeroen Mostert commented, you need to make everything dynamic.
I would suggest to put the join inside the dynamic query. Instead of a table variable, I use a common table expression.
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX);
SELECT #cols =
STUFF((SELECT DISTINCT N', ' + QUOTENAME([ColName])
FROM [_tmp_].[ProposalAmounts]
GROUP BY [ColName], [ProposalID]
FOR XML PATH(N''), TYPE).value(N'.', N'NVARCHAR(MAX)'), 1, 2, N'')
SET #query = N'
WITH [CTE_Pivoted_ProposalAmounts] AS
(
SELECT [ProposalID], ' + #cols + N'
FROM
(SELECT [ProposalID], [Amount], [ColName] FROM [sbs].[ProposalAmounts]) x
PIVOT (MAX([Amount]) FOR [ColName] IN (' + #cols + N')) p
)
SELECT *
FROM
[sbs].[OtherTable] ot
INNER JOIN [CTE_Pivoted_ProposalAmounts] ppa ON ppa.[ProposalID] = ot.[ProposalID];
';
EXEC sp_executesql #query;
You need to replace [sbs].[OtherTable] with the actual name of the table you want to join with. And you might also tweak the join criteria and the fields in the SELECT clause. This code here is just a simple example. I assume you will manage to fix the query yourself to make it behave as you expect.
I have the following data in a table with columns Col1,Col2,Col3,Col4, Col5......... Col153
The sample data in the first four columns in the table:
CREATE TABLE dbo.MyTable (LocaID VARCHAR(10),Col1 INT, Col2 INT,Col3 INT,Col4 INT)
INSERT INTO dbo.MyTable values
('LV',2,6,4,7),('CH',4,8,3,1),('LV',1,3,9,3),('MC',7,0,5,4),
('LV',4,5,2,4),('MC',7,1,4,9),('MC',5,1,8,1),('CH',7,3,4,0),
('MC',2,5,7,3);
There are 153 columns that I need to sum individually. I used the query below to get the list of columns:
-- This is to get the columns names
SELECT
COLUMN_NAME AS Col_Names
INTO #Column
From INFORMATION_SCHEMA.COLUMNS
Where TABLE_NAME Like 'MyTable'
I tried to use the query below to dynamically sum them:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(Col_Names)
FROM #Column
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #query= 'SELECT
SUM('+#cols+')
FROM dbo.MyTable GROUP BY [LocaID]'
PRINT #query
When I print the result to check if the query is correct I got this:
SELECT SUM([Col1],[Col2],[Col3],[Col4],[LocaID])
FROM dbo.MyTable GROUP BY [LocaID]
Which is clearly not correct. What I need is:
SELECT
[LocaID],
SUM([Col1]) AS [Col1],
SUM([Col2]) AS [Col2],
SUM([Col3]) AS [Col3],
SUM([Col4]) AS [Col4]
FROM dbo.MyTable
GROUP BY [LocaID]
For all the 153 columns. There is only one LocaID in the table.
If you want to SUM individual column, you need to change your STUFF function. You need to apply SUM function for all the columns, like below.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',SUM(' + QUOTENAME(Col_Names) + ')'
FROM #Column
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)') ,1,1,'')
SET #query= 'SELECT [LocaID], '+#cols+'
FROM dbo.MyTable GROUP BY [LocaID]'
PRINT #query
Thanks you so much #Vad Soft, I adjusted you query to give me what i want
DECLARE #cols AS NVARCHAR(MAX),
#cols2 AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((
----------------------------------------------------------------------------------
SELECT DISTINCT CONCAT(',SUM(' + QUOTENAME(a.Col_Names) + ') AS ',' ',b.RN)
FROM #Column a
LEFT JOIN
(
SELECT
Col_Names AS RN
from #Column
where Col_Names <> 'LocaID' ) b ON b.RN=a.Col_Names
-------------------------------------------------------------------------------------
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)') ,1,1,'')
SET #cols2 =REVERSE(RIGHT(REVERSE(#cols),LEN(REVERSE(#cols))- CHARINDEX(',',REVERSE(#cols))))
--PRINT #cols2
SET #query= 'SELECT [LocaID],
'+#cols2+'
FROM dbo.MyTable GROUP BY [LocaID]'
--PRINT #cols
EXEC (#query)
---------------------------
DROP TABLE #Column
Output
print #query
SELECT [LocaID],
SUM([Col1]) AS Col1,
SUM([Col2]) AS Col2,
SUM([Col3]) AS Col3,
SUM([Col4]) AS Col4
FROM dbo.MyTable GROUP BY [LocaID]
I am trying to cross join two pivot tables.
--First Pivot table query gets columns of drug_names and produces the row value
--of the drug_id.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
Select #cols = STUFF((SELECT ',' + QUOTENAME(drug)
from _app_drugs
group by drug, drug_id,order_number
order by order_number
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = N'SELECT ' + #cols + N' from
(
select drug_id, drug
from _app_drugs
) x
pivot
(
max(drug_id)
for drug in (' + #cols + N')
) p'
exec sp_executesql #query;
--The second pivot table simply gets the signature_labels and displays the label name in the column and displays the label_id as the row value.
DECLARE #cols AS NVARCHAR(MAX),#scols as NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
Select #cols = STUFF((SELECT ',' + QUOTENAME(signature_label)
from _app_signature_labels
WHERE _app_signature_labels.isactive=1
group by signature_label_id, signature_label,ordernumber
order by ordernumber
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = N'SELECT ' + #cols + N' from
(
select signature_label_id,signature_label
from _app_signature_labels
) x
pivot
(
max(signature_label_id)
for signature_label in (' + #cols + N')
) p'
exec sp_executesql #query;
Now I just need to know how to combine these two pivot tables as one table... they don't have a common field and don't need one.
Can anybody help me with this one?
Thank you
You can execute two separate dynamic SQL statements into two global temp tables and then combine the result, like this:
IF object_id('tempdb..##tmpResult1') IS NOT NULL
BEGIN
DROP TABLE ##tmpResult1
END
IF object_id('tempdb..##tmpResult2') IS NOT NULL
BEGIN
DROP TABLE ##tmpResult2
END
DECLARE #cols AS NVARCHAR(MAX),
#cols2 AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#query2 AS NVARCHAR(MAX)
Select #cols = STUFF((SELECT ',' + QUOTENAME(drug)
from _app_drugs
group by drug, drug_id,order_number
order by order_number
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = N'SELECT ' + #cols + N' INTO ##tmpResult1 from
(
select drug_id, drug
from _app_drugs
) x
pivot
(
max(drug_id)
for drug in (' + #cols + N')
) p'
exec sp_executesql #query;
--The second pivot table simply gets the signature_labels and displays the label name in the column and displays the label_id as the row value.
Select #cols2 = STUFF((SELECT ',' + QUOTENAME(signature_label)
from _app_signature_labels
WHERE _app_signature_labels.isactive=1
group by signature_label_id, signature_label,ordernumber
order by ordernumber
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query2 = N'SELECT ' + #cols2 + N' INTO ##tmpResult2 from
(
select signature_label_id,signature_label
from _app_signature_labels
) x
pivot
(
max(signature_label_id)
for signature_label in (' + #cols2 + N')
) p'
exec sp_executesql #query2;
SELECT * FROM ##tmpResult1 t1
INNER JOIN ##tmpResult2 t2 ON t1.ordernumber = t2.ordernumber
This is also a way to address this error when doing a large PIVOT query: Internal error: An expression services limit has been reached. Please look for potentially complex expressions in your query, and try to simplify them.
I have the following which I would like to be a View, but the Declare statement is not allowed apparently.
What is the best solution/work-around to this problem?
I'm using SQL Server. I have tried many other solutions (Stored Procedures, Table-Values Functions), but I think the combination of Dynamic SQL is complicating the matter and I haven't been able to get anything working.
DECLARE #cols AS NVARCHAR(MAX),
#colsAlias AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
select #cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(MeasurementTypeID)
FROM dbo.Measurements
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SELECT #colsAlias = STUFF((SELECT DISTINCT ',' + QUOTENAME(dbo.Measurements.MeasurementTypeID) + ' AS ' + QUOTENAME(dbo.MeasurementTypes.MeasurementType)
FROM dbo.Measurements INNER JOIN dbo.MeasurementTypes ON dbo.Measurements.MeasurementTypeID = dbo.MeasurementTypes.MeasurementTypeID
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
SET #query = 'SELECT NeuronID, ' + #colsAlias +' FROM
(
SELECT MeasurementName, MeasurementValue, NeuronID, MeasurementTypeID
FROM dbo.Measurements
) x
PIVOT
(
MIN(MeasurementValue) FOR MeasurementTypeID IN (' + #cols + ')
) AS p'
EXECUTE(#query)
I have a dynamic pivot written as below, I need to add a where clause
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),#uniqId varchar(50);
set #uniqId = 'IN0s3Z0n8z4v'
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.DisplayLabel)
FROM [dbo].[CountyCaseUserData] c where UniqueEntryId = #uniqId
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
print #cols
set #query = 'SELECT ' + #cols + '
from
(
SELECT UserInput, DisplayLabel,row_number()
over (partition by DisplayLabel order by CCId) AS No
from [dbo].[CountyCaseUserData] where UniqueEntryId = #uniqId
) x
pivot
(
max(UserInput)
for DisplayLabel in (' + #cols + ')
) p ';
execute(#query)
But when executing, I get a message
Must declare the scalar variable "#uniqId"
What am I missing here?
as what others pointed out,
change execute(#query)
to
exec sp_executesql #query, N'#uniqId varchar(50)', #uniqId