使用 While 循环在每次迭代中使用由变量定义的列名来更新每列的值

问题描述 投票:0回答:1

我正在构建每日交付报告,以取代使用纸质清单和 Excel 手动编译的流程。我想我应该把我的组织带入 21 世纪。我的一些设计选择被锁定,因为报告需要与现有报告相同。为了实现这一目标,我为每种交付类型创建了一个临时表,其中按一天中的小时进行计数:

CREATE TABLE #TempTable (
    [Date] DATE,
    HourRange INT,
    Dole INT DEFAULT 0,
    Harborside INT DEFAULT 0,
    Bauxite INT DEFAULT 0,
    Sugar INT DEFAULT 0,
    Fertilizer INT DEFAULT 0,
    Cement INT DEFAULT 0,
    [Auto Carriers] INT DEFAULT 0,
    [High/Wide] INT DEFAULT 0,
    [Flat Bed] INT DEFAULT 0,
    [Non-Cargo] INT DEFAULT 0
);

-- Calculate the date for the previous day
DECLARE @PreviousDay DATE = DATEADD(DAY, -1, GETDATE());

-- Generate hour ranges for the previous day, starting from 0
DECLARE @Hour INT = 0;

WHILE @Hour <= 23 -- Change this to generate hours from 0 to 23
BEGIN
    INSERT INTO #TempTable ([Date], HourRange)
    VALUES (@PreviousDay, @Hour);
    
    SET @Hour = @Hour + 1;
END

这会产生这样的表格:

Date    HourRange   Dole    Harborside  Bauxite Sugar   Fertilizer  Cement  Auto Carriers   High/Wide   Flat Bed    Non-Cargo
2023-10-21  0   0   0   0   0   0   0   0   0   0   0   
2023-10-21  1   0   0   0   0   0   0   0   0   0   0   
2023-10-21  2   0   0   0   0   0   0   0   0   0   0   
2023-10-21  3   0   0   0   0   0   0   0   0   0   0   
2023-10-21  4   0   0   0   0   0   0   0   0   0   0   
2023-10-21  5   0   0   0   0   0   0   0   0   0   0   
2023-10-21  6   0   0   0   0   0   0   0   0   0   0   
2023-10-21  7   0   0   0   0   0   0   0   0   0   0   
2023-10-21  8   0   0   0   0   0   0   0   0   0   0   
2023-10-21  9   0   0   0   0   0   0   0   0   0   0   
2023-10-21  10  0   0   0   0   0   0   0   0   0   0   
2023-10-21  11  0   0   0   0   0   0   0   0   0   0   
2023-10-21  12  0   0   0   0   0   0   0   0   0   0   
2023-10-21  13  0   0   0   0   0   0   0   0   0   0   
2023-10-21  14  0   0   0   0   0   0   0   0   0   0   
2023-10-21  15  0   0   0   0   0   0   0   0   0   0   
2023-10-21  16  0   0   0   0   0   0   0   0   0   0   
2023-10-21  17  0   0   0   0   0   0   0   0   0   0   
2023-10-21  18  0   0   0   0   0   0   0   0   0   0   
2023-10-21  19  0   0   0   0   0   0   0   0   0   0   
2023-10-21  20  0   0   0   0   0   0   0   0   0   0   
2023-10-21  21  0   0   0   0   0   0   0   0   0   0   
2023-10-21  22  0   0   0   0   0   0   0   0   0   0   
2023-10-21  23  0   0   0   0   0   0   0   0   0   0

一天中每小时一行,用于统计每种货物类型。

我现在想通过连接三个表(Visits、VisitCargo、Cargo)的查询来填充这些计数。 Visits 包含访问时间和车辆信息,Cargo 是我们跟踪的货物类型的表格,VisitCargo 可以调解可能的多对多关系,以防一次访问有多个与之相关的货物。我想从 VisitCargo 中获取计数并将其应用到我上面构建的 TempTable 中。

为了实现这一目标,我构建了一个 WHILE 循环来迭代货物类型,以便更新每个货物名称的表。在每个循环中,我希望它会更新所选的 CargoName 并更新其列。当我制作原型时,我可以让它更新得很好。当我将变量作为 SET 命令的一部分引入时,一切都崩溃了。我尝试使用dynamicSQL,但现在遇到数据类型错误。

DECLARE @CargoOrder INT;

-- Create a cursor to iterate through unique CargoName values
DECLARE CargoCursor CURSOR FOR
SELECT DISTINCT CargoOrder
FROM Cargo
WHERE CargoName not like 'Test%';

-- Open the cursor
OPEN CargoCursor;

-- Fetch the first CargoName
FETCH NEXT FROM CargoCursor INTO @CargoOrder;

-- Start looping through unique CargoName values
WHILE @@FETCH_STATUS = 0
BEGIN
    DECLARE @CargoName NVARCHAR(MAX);
    DECLARE @sql NVARCHAR(MAX);
    SELECT @CargoName = CargoName FROM [dbo].[Cargo] WHERE CargoOrder = @CargoOrder
    -- Construct the dynamic SQL query for each CargoName
    SET @sql = 'UPDATE #TempTable
    SET ' + @CargoName + ' = ISNULL((SELECT CargoCount FROM (
        SELECT ' + @CargoName + ' AS CargoName, DATEPART(HOUR, V.VisitStart_Time) AS HourOfDay,
            COUNT(*) AS CargoCount
        FROM [dbo].[Visit] V
        JOIN [dbo].[VisitCargo] C ON V.GUID = C.VisitGUID
        JOIN [dbo].[Cargo] O ON O.GUID = C.CargoGUID
        WHERE VisitStart_Time >= CAST(GETDATE() - 1 AS DATE) AND VisitStart_Time < CAST(GETDATE() AS DATE)
            AND O.CargoName = ' + @CargoName + '
        GROUP BY DATEPART(HOUR, V.VisitStart_Time)
    ) AS Subquery WHERE Subquery.HourOfDay = #TempTable.HourRange), 0)
WHERE [Date] = CAST(GETDATE() - 1 AS DATE);' -- Adjust the date as needed
    EXEC(@sql);
    -- Fetch the next CargoName
    FETCH NEXT FROM CargoCursor INTO @CargoOrder;
END

-- Close and deallocate the cursor
CLOSE CargoCursor;
DEALLOCATE CargoCursor;

-- Select the results from the temporary table
SELECT * FROM #TempTable;

运行此查询时遇到的错误是:

消息 245,第 16 级,状态 1,第 1 行 将 nvarchar 值“Dole”转换为数据类型 int 时转换失败。

有什么建议吗?

sql sql-server dynamic-sql
1个回答
0
投票

谢谢戴尔·K 您对调试变量内容的建议使我能够找到问题所在:

AND O.CargoName = ' + @CargoName + '

这是错误的,并且将 @CargoName 解析为 INT 数据类型比较(事实并非如此)。我需要单引号。 所以我把它改为:

AND O.CargoName = ''' + @CargoName + ''' 

它解决了这个问题。再次感谢戴尔 K。

© www.soinside.com 2019 - 2024. All rights reserved.