I want to use group by functionality with dynamic value.
Ex:
x
CREATE PROCEDURE getEmpStats (@COLUMN_NAME VARCHAR(20))
AS
BEGIN
DECLARE @DUPLICATE_COUNTS INT
BEGIN
SELECT @DUPLICATE_COUNTS = SUM(DUP_COUNTS)
FROM
(SELECT COUNT(*) AS DUP_COUNTS
FROM emp
GROUP BY @COLUMN_NAME) AS A
-------------------
END
END
When I code like this I get the error == >
Each GROUP BY expression must contain at least one column that is not an outer reference.
Any workaround for this?
Advertisement
Answer
You need to be very careful with this type of code as it is prone to SQL injection.
Always use QUOTENAME
on identifiers. And if the column name is coming from user code then verify it.
Because @DUPLICATE_COUNTS
is not in scope in the dynamic part, you need to re-declare it as an OUTPUT
parameter.
CREATE PROCEDURE getEmpStats (@COLUMN_NAME varchar(20))
AS
DECLARE @DUPLICATE_COUNTS int;
DECLARE @sql nvarchar(max) = N'
SELECT @DUPLICATE_COUNTS = SUM(DUP_COUNTS)
FROM
(SELECT COUNT(*) AS DUP_COUNTS
FROM emp
GROUP BY ' + QUOTENAME(@COLUMN_NAME) + N') AS A;
';
EXEC sp_executesql @sql, N'@DUPLICATE_COUNTS int OUTPUT', @DUPLICATE_COUNTS = @DUPLICATE_COUNTS
GO
To verify the column name, use this code:
IF (NOT EXISTS (SELECT 1
FROM sys.columns c
WHERE c.name = @COLUMN_NAME AND c.object_id = OBJECT_ID(N'emp')
))
THROW 50000, 'Non existent column', 0;