【问题标题】:Procedure with cursor for counting a number of orders before a given date使用光标计算给定日期之前的订单数量的过程
【发布时间】:2021-10-28 05:23:17
【问题描述】:

检查在给定日期之前是否有任何订单(Date 列)。该过程有一个作为日期的传递参数“date”和另一个传递参数“count”。此参数返回此日期之前的订单数。

简单的做法是:

SELECT COUNT([Sales].[dbo].[Order].[Date])
FROM [Sales].[dbo].[Order]
WHERE [Sales].[dbo].[Order].[Date] >= '2019-03-11'

但不幸的是我必须使用程序和光标。我的尝试是这样的:

CREATE OR ALTER PROCEDURE OrderBeforeDate
    (@date date, 
     @count int OUT)
AS
BEGIN
    SET @count = 0;

    DECLARE cursor1 SCROLL CURSOR FOR
        SELECT [Sales].[dbo].[Order].[Date] 
        FROM [Sales].[dbo].[Order]
        FOR READ ONLY

    OPEN cursor1;

    FETCH NEXT FROM cursor1 INTO @date

    WHILE @@FETCH_STATUS = 0
    BEGIN
        IF @date <= '2019-03-11'
            SET @count = @count + 1;
    END

    CLOSE cursor1;
    DEALLOCATE cursor1;
END

DECLARE @count int

EXEC OrderBeforeDate @count OUT

PRINT 'Number of Orders after 2019-03-11'': ' + CAST(@count AS VARCHAR(10))

但我收到以下错误消息:

操作数类型冲突:int 与日期不兼容

我不知道该怎么办。请帮我一把。

【问题讨论】:

  • 为什么要在这里使用光标? SQL 是一种基于集合的语言,在极少数情况下您应该使用它。
  • 我完全同意你的看法,但这是该项目所需的默认设置。
  • 听起来像一个非常有缺陷的项目,需要一个光标来完成这样的事情。
  • 您的存储过程逻辑有缺陷。您有一个日期参数,但您没有正确使用它。您可以在游标定义中包含该参数,然后只计算它返回的行数。或者,您可以根据日期参数评估游标返回的每一行的日期,并根据需要递增。第二种方法 - 这是您实现的 - 需要另一个局部变量来接受来自光标的适当列。然后将您的参数与此局部变量进行比较。
  • 还有一个坏习惯 - 使用 3 部分名称。过程通常存在于特定数据库中,并且将引用同一数据库中的对象(表)。使用三部分名称意味着更改数据库名称将需要更改代码。数据库名称更改很常见 - 不要在没有充分理由的情况下使用 3 部分名称。

标签: sql sql-server count cursor procedure


【解决方案1】:

您没有传递预期的参数。我希望在你的模型中看到

DECLARE @count int=0, @Date date='20190311'

EXEC OrderBeforeDate @Date, @count OUT

PRINT 'Number of Orders after 2019-03-11: ' + CAST(@count AS VARCHAR(10))

我还要指出(您可能已经知道)这个游标除了限制 SQL Server 性能之外没有其他用途。

此外,您的程序正在计算日期值之前的行数,而您的 print 语句则相反。

【讨论】:

    【解决方案2】:

    在调用 OrderBeforeDate 过程时,您可能错过了给出日期参数的值。您只传入 1 个参数,SQL 服务器可能会将 @count 值视为日期参数的值。

    EXEC OrderBeforeDate @count OUT
    

    【讨论】:

      【解决方案3】:

      您的存储过程需要 2 个参数,而您只提供一个。缺少日期参数。 你的光标有无限循环,你的程序永远不会结束

      为此使用游标是一个非常糟糕的主意,请将您的计数放入排序过程中

      【讨论】:

      • 请添加更多详细信息以扩展您的答案,例如工作代码或文档引用。
      【解决方案4】:

      感谢您的所有意见!我认为它现在可以使用如下代码:

      CREATE OR ALTER PROC OrderBeforeDate(@date date, @count int out)
      AS
      BEGIN
      
      SET @count = 0;
      
      DECLARE cursor1 scroll cursor for
      SELECT [Sales].[dbo].[Order].[Date] 
      FROM [Sales].[dbo].[Order]
      FOR READ ONLY
      
      OPEN cursor1;
      FETCH NEXT FROM cursor1 INTO @date
      WHILE @@FETCH_STATUS = 0
      BEGIN
      IF @date < '2019-03-11'
          SET @count = @count + 1;
          FETCH NEXT FROM cursor1 INTO @date
      END
      
      CLOSE cursor1;
      DEALLOCATE cursor1;
      
      END
      
      
      DECLARE @count int
      DECLARE @date date
      EXEC OrderBeforeDate @date, @count OUT
      
      PRINT 'Number of Orders before 2019-03-11: ' + CAST(@count AS VARCHAR(10))
      

      你说得对,这种方法比我一开始提到的方法要慢得多。 (1 分钟与不到 1 秒) 感谢大家的帮助!

      【讨论】:

        猜你喜欢
        • 2019-07-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-02
        相关资源
        最近更新 更多