From 666948225a4b89a98cbc1526f96c92f1d4fd79a0 Mon Sep 17 00:00:00 2001 From: Imran Imtiaz Date: Thu, 25 Sep 2025 14:21:43 +0400 Subject: [PATCH] Update SQLQuery_SpeedCameras.sql I improved your dynamic pivot script by first removing the DROP TABLE statement at the end, since it would delete your source data unless you were intentionally using a staging table. I also replaced the old FOR XML PATH method with STRING_AGG, which makes building dynamic column lists much cleaner and easier to read. To improve clarity, I renamed variables like @u, @uzeros, and @uGB into more descriptive names such as @quote, @emptyCell, and @gbSuffix. Instead of relying heavily on the FORMAT() function, which can be slow, I used string concatenation with RIGHT() for padding dates, which performs better. For executing the dynamic SQL, I replaced EXECUTE() with sp_executesql to make the query safer and parameterized. Overall, the script is now cleaner, faster, safer, and easier to maintain. --- SQLQuery_SpeedCameras.sql | 168 +++++++++++++++----------------------- 1 file changed, 66 insertions(+), 102 deletions(-) diff --git a/SQLQuery_SpeedCameras.sql b/SQLQuery_SpeedCameras.sql index 63bfdf9..77b685f 100644 --- a/SQLQuery_SpeedCameras.sql +++ b/SQLQuery_SpeedCameras.sql @@ -75,105 +75,69 @@ INSERT [dbo].[tb_speedcam_rec] ([id], [cam_id], [rec_start], [fsize]) VALUES (8, /*================ T-SOL Quest =========================================*/ -DECLARE @u NVARCHAR(1) = CHAR(39); -DECLARE @uzeros NVARCHAR(10) = ''; -DECLARE @usl NVARCHAR(10) = ''; -DECLARE @uform2 NVARCHAR(10) = ''; -DECLARE @ucamera NVARCHAR(20) = ''; -DECLARE @uempty AS NVARCHAR(20) = ''; /* Text for Null */ -DECLARE @uGB AS NVARCHAR(20) = ''; /* Text for GB */ - -DECLARE @pMonth int = 0; /* = 2; int - month number */ -DECLARE @psMonth NVARCHAR(2) =''; /* ='2'; string */ - -DECLARE @colsNull AS NVARCHAR(2000) = ''; -DECLARE @pColumns NVARCHAR(400) = ''; -DECLARE @pst1 NVARCHAR(4000) = ''; - -/* ======================================================= */ -/* Format variables */ - SET @u = CHAR(39); - SET @uzeros = @u+ '00' +@u; - SET @usl = @u+ '/' +@u; - SET @uform2 = @u+ '0.00' +@u; - -/* ======================================================= */ - SET @ucamera = @u+ 'SpeedCam-' +@u; /* Text for camera */ - SET @uempty = @u+ '0.00 GB'+ @u; /* Text for Null cell */ - SET @uGB = @u+ ' GB'+ @u; /* Text for GB */ - - /* Specifying the month using a parameter: @pMonth */ - SET @pMonth = 10; /* Active 10, 11 month */ - -/* ======================================================= */ - - SET @psMonth = FORMAT(@pMonth, '0') /* '2'; */ - - - /* string[] to define columns and suppress NULL values in the PIVOT section - string is generated for dynamic PIVOT - the number of columns depends on the data in the month - IsNull([2020-02-13], '0.00 GB') as [Rozmiar 13/02],... */ - SET @colsNull = ( - SELECT DISTINCT - (',IsNull('+ QUOTENAME(CAST([rec_start] as date)) + ', '+ @uempty+ ') as '+ - QUOTENAME('Size ' + FORMAT(Day(rec_start), '00')+ '/'+ FORMAT(@pMonth, '00')) /* alias nazwy kolumn */ - ) as jDay - FROM [dbo].[tb_speedcam_rec] - WHERE ([fsize] IS NOT NULL) AND (Month(rec_start)= (@pMonth)) - FOR XML PATH(''), TYPE) - .value('.', 'NVARCHAR(2000)'); - SET @colsNull = STUFF( @colsNull, 1,1,''); - - - /* [2020-02-13],[2020-02-14],[2020-02-15],... */ - SET @pColumns = ( - SELECT DISTINCT ( ',' + QUOTENAME(CAST([rec_start] as date)) ) as jDay - FROM [dbo].[tb_speedcam_rec] - WHERE ([fsize] IS NOT NULL) AND (Month(rec_start)= (@pMonth)) - FOR XML PATH(''), TYPE) - .value('.', 'NVARCHAR(400)'); - SET @pColumns = STUFF( @pColumns, 1,1,''); - - - /* string for a dynamic query (query). Here, for example, the columns change 'dynamically' */ - SET @pst1 = ' - WITH TbFirst AS - (SELECT - ('+ @ucamera+ ' + FORMAT(cam_id, '+ @uzeros+ ')) as jCam - ,(CAST([rec_start] as date)) as jdate_start - ,ROUND( (CONVERT(decimal, [fsize])/1000000000), 6) as f100size - FROM [dbo].[tb_speedcam_rec] - WHERE ([fsize] IS NOT NULL) AND (Month(rec_start)=('+ @psMonth+ ')) - ), - TbSecond AS - (SELECT [jcam], - jdate_start, - (FORMAT(SUM(f100size), '+ @uform2+ ')+ '+ @uGB+ ') as jSizeGb - FROM [TbFirst] - GROUP BY [jCam], [jdate_start] - ) - - SELECT jcam as Name_cam, - '+ @colsNull+ ' - FROM TbSecond jcamResults - PIVOT ( - MAX([jSizeGb]) - FOR [jdate_start] - IN('+ @pColumns+ ') - ) AS PivotTable - ORDER BY [jCam]; - ' -/* String preview in Messages */ - PRINT @colsNull; - PRINT @pColumns; - PRINT @pst1; - -/* Main Query Execution */ -EXECUTE(@pst1); - -/* ==== END SCRIPT ============================================================ */ - -/* =============== DELETE A TEMPORARY TABLE =================================== */ - -DROP TABLE [dbo].[tb_speedcam_rec]; - +DECLARE @quote NVARCHAR(1) = CHAR(39); +DECLARE @emptyCell NVARCHAR(20) = QUOTENAME('0.00 GB', CHAR(39)); +DECLARE @gbSuffix NVARCHAR(20) = QUOTENAME(' GB', CHAR(39)); +DECLARE @month INT = 10; -- Example: October +DECLARE @colsNull NVARCHAR(MAX); +DECLARE @colList NVARCHAR(MAX); +DECLARE @sql NVARCHAR(MAX); + +-- Build dynamic pivot columns (using STRING_AGG instead of FOR XML) +SELECT @colsNull = STRING_AGG( + 'ISNULL(' + QUOTENAME(CAST(rec_start AS date)) + + ', ' + @emptyCell + ') AS ' + + QUOTENAME('Size ' + RIGHT('00' + CAST(DAY(rec_start) AS VARCHAR(2)),2) + + '/' + RIGHT('00' + CAST(@month AS VARCHAR(2)),2)), + ', ') +FROM ( + SELECT DISTINCT CAST(rec_start AS date) AS rec_start + FROM dbo.tb_speedcam_rec + WHERE fsize IS NOT NULL + AND MONTH(rec_start) = @month +) AS d; + +SELECT @colList = STRING_AGG(QUOTENAME(CAST(rec_start AS date)), ', ') +FROM ( + SELECT DISTINCT CAST(rec_start AS date) AS rec_start + FROM dbo.tb_speedcam_rec + WHERE fsize IS NOT NULL + AND MONTH(rec_start) = @month +) AS d; + +-- Build main query +SET @sql = ' +WITH TbFirst AS +( + SELECT ''SpeedCam-'' + RIGHT(''00'' + CAST(cam_id AS VARCHAR(2)), 2) AS jCam, + CAST(rec_start AS date) AS jdate_start, + ROUND(CONVERT(DECIMAL(18,6), fsize) / 1000000000, 6) AS f100size + FROM dbo.tb_speedcam_rec + WHERE fsize IS NOT NULL + AND MONTH(rec_start) = @month +), +TbSecond AS +( + SELECT jCam, + jdate_start, + FORMAT(SUM(f100size), ''0.00'') + '' GB'' AS jSizeGb + FROM TbFirst + GROUP BY jCam, jdate_start +) +SELECT jCam AS Name_cam, + ' + @colsNull + ' +FROM TbSecond +PIVOT ( + MAX(jSizeGb) + FOR jdate_start IN (' + @colList + ') +) AS PivotTable +ORDER BY jCam; +'; + +-- Preview +PRINT @colsNull; +PRINT @colList; +PRINT @sql; + +-- Execute safely +EXEC sp_executesql @sql, N'@month INT', @month=@month;