如何在SELECT语句中对函数产生影响时替换CURSOR

Ari*_*ian -3 sql sql-server cursor sql-server-2014

请考虑以下代码:

Declare @MyMinMaxTable Table
(
    [Min]    int,
    [Max]    int,
    [Desc]   NVARCHAR(50)
)

Insert into @MyMinMaxTable
values (0,12,N'Child'),
       (13,19,N'Teenager'),
       (20,25,N'Youth'),
       (25,40,N'Middle-aged'),
       (40,99,N'Old')

Declare @MyTable Table
(
    Id         int identity(1,1),
    [Year]     int,
    Age        int,
    MyCol2     int,
    MyCol3     int null
)

Insert into @MyTable
([Year], Age, MyCol2, MyCol3)
values 
(2012, 10, 1 , 1),
(2012, 28, 2 , 3),
(2012, 14, 1 , 7),
(2012, 24, 3 , 3),
(2012, 80, 1 , 6),
(2012, 39, 1 , 3),
(2012, 45, 1 , 5),
(2012, 23, 2 , 6),
(2012, 72, 3 , 8),
(2012, 17, 1 , null),
(2012, 62, 4 , 9),
(2012, 20, 1 , null),
(2012, 5, 1 , 9),
(2012, 8, 1 , 9),
(2012, 25, 1 , null),
(2012, 41, 2 , 2),
(2012, 26, 1 , 2),
(2012, 33, 4 , 2),
(2012, 40, 1 , 2),
(2012, 33, 2 , 3),
(2012, 41, 1 , 5),
(2012, 53, 1 , null),
(2012, 37, 1 , 3)

Declare @Result Table
(
    C0         NVARCHAR(50),
    c1         decimal(5,2),
    C2         decimal(5,2),
    C3         decimal(5,2)
)
Run Code Online (Sandbox Code Playgroud)

CURSOR部分:

DECLARE @Min    int;
DECLARE @Max    int;
DECLARE @Desc   nvarchar(50);

DECLARE mycur CURSOR  
FOR
    SELECT [min],
           [max],
           [Desc]
    FROM   @MyMinMaxTable
OPEN mycur

FETCH NEXT FROM mycur INTO @Min, @Max, @Desc

WHILE (@@fetch_status = 0)
    BEGIN
        INSERT INTO @Result
        SELECT @Desc As c0,
               (Cast(COUNT(CASE when Age >= @Min AND Age <= @Max  THEN 1 END) as decimal(5,2)) / cast(COUNT(Id) as decimal(5,2))) As c1,
               (Cast(COUNT(CASE when MyCol2 = 1 AND MyCol3 IS NOT NULL THEN 1 END) as decimal(5,2))  / cast(COUNT(CASE when Age >= @Min AND Age <= @Max  THEN 1 END) as decimal(5,2))) As c2,
               (Cast(COUNT(CASE when Age >= @Min AND Age <= @Max  ANd MyCol2 = 1 THEN 1 END) as decimal(5,2)) / cast(COUNT(CASE when MyCol2 = 1 THEN 1 END) as decimal(5,2))) As c3
        FROM   @MyTable AS td

    FETCH NEXT FROM mycur INTO @Min, @Max, @Desc
END 

CLOSE mycur
DEALLOCATE mycur

SELECT * FROM @Result
Run Code Online (Sandbox Code Playgroud)

问题是我想删除CURSOR并编写没有它的查询.在这种情况下它怎么可能?

Dan*_*n D 5

尝试一下CROSS JOIN并过滤where子句或条件CASE语句.目前还不清楚你的最终目标是什么,所以下面的总量必须调整,但这可能是一个好的开始:

SELECT 
  mm.[Desc],
  (CAST(SUM(CASE WHEN MyCol1 >= mm.Min AND MyCol1 <= mm.Max THEN 1 ELSE 0 END) AS DECIMAL(5,2)) / CAST(COUNT(Id) AS DECIMAL(5,2))) AS C1,
  (CAST(SUM(CASE WHEN MyCol2 = 1 AND MyCol3 IS NOT NULL THEN 1 END) AS DECIMAL(5,2)) / CAST(SUM(CASE WHEN MyCol1 >= mm.Min AND MyCol1 <= mm.Max THEN 1 ELSE 0 END) AS DECIMAL(5,2))) AS C2,
  (CAST(SUM(CASE WHEN MyCol1 >= mm.Min AND MyCol1 <= mm.Max AND MyCol2 = 1 THEN 1 ELSE 0 END) AS DECIMAL(5,2)) / CAST(SUM(CASE WHEN MyCol2 = 1 THEN 1 ELSE 0 END) AS DECIMAL(5,2))) AS C3
FROM MyTable td
  CROSS JOIN MyMinMaxTable mm
GROUP BY mm.[Desc]
Run Code Online (Sandbox Code Playgroud)

  • 你问了一个替代方案并给了一个,执行计划是另一回事,因为我们不知道你的数据库是什么样的以及它的索引方式.那部分取决于你.您可以随时使用此示例并进行调整,但我们不负责为您执行工作. (3认同)
  • @TheGameiswar,这个答案中的查询确实产生了与问题中光标相同的结果.不同之处在于舍入,因为游标代码插入带有`decimal(5,2)`列的`@ Result`表,并且此答案中的查询不会将比率的最终结果转换为`decimal(5) ,2)`和结果有更多小数位. (3认同)
  • @Arian:交叉连接的执行是一个基于集合的操作,它比你的逐行方法要好得多. (2认同)
  • 上面的答案取代了你的光标,不是吗?,它比逐行操作要好得多 (2认同)