【问题标题】:Stored procedure only executes correctly on first execution存储过程仅在第一次执行时正确执行
【发布时间】:2020-04-17 19:19:08
【问题描述】:

我编写了这个 SQL Server 存储过程,它根据客户在另一个表中的订购频率将记录插入到另一个表中。它根据每个客户的订单频率为他们分配一个排名。当我第一次创建过程并执行它时,它工作正常并将正确的记录插入到表中。但是当我清除表并尝试再次执行该过程时,没有添加任何记录。我必须删除该过程,重新启动 SSMS,然后再次创建该过程,它才能再次正常工作。

程序如下:

create procedure TopKCustomer (@CustRank decimal(11,0))
as
    declare CustCursor cursor local for
        select o.CustomerID,c.CustomerName,c.CustomerPostalCode,
            count(o.CustomerID) as 'Order Frequency'
        from (Customer_T c join Order_T o on c.CustomerID=o.CustomerID) 
        group by o.CustomerID,c.CustomerName,c.CustomerPostalCode
        order by [Order Frequency] desc;

    declare @PrevOrderFreq float;
    declare @CurrOrderFreq float;
    declare @CurrRank decimal(11,0);
    declare @CurrCustID decimal(11,0);
    declare @CurrCustName varchar(25);
    declare @CurrCustPostCode varchar(10);

begin
    set @PrevOrderFreq = 0;
    set @CurrOrderFreq = 0;
    set @CurrRank = 0;
    set @CurrCustID = 0;
    set @CurrCustName = '';
    set @CurrCustPostCode = '';

    open CustCursor;

    while @@FETCH_STATUS = 0
    begin
        fetch next from CustCursor into @CurrCustID, @CurrCustName, @CurrCustPostCode, @CurrOrderFreq;

        if @CurrOrderFreq <> @PrevOrderFreq
        begin
            set @CurrRank = (@CurrRank + 1);

            if @CurrRank > @CustRank
            begin
                break;
            end
        end

        insert into TopKCustomer_T
        values (@CurrCustID, @CurrCustName, @CurrCustPostCode, @CurrRank, getdate());

        set @PrevOrderFreq = @CurrOrderFreq;
    end

    close CustCursor;
    deallocate CustCursor;
end

这是我正在使用的表格:

  • Customer_T (CustomerID, CustomerName, CustomerAddress, CustomerCity, CustomerState, CustomerPostalCode)
  • Order_T(OrderID、CustomerID、OrderDate)
  • TopKCustomer(CustomerID、CustomerName、CustomerPostalCode、CRank、RankGenerateDate)

【问题讨论】:

  • 哇....光标。为什么??? SQL 是一种基于集合的语言。您不会一个一个地循环每个记录。
  • 是光标造成的问题吗?
  • 你可以谷歌一下。这不是循环记录的正确方法。
  • @user10605996 答案之一是否解决了您的问题?如果是,请考虑接受。

标签: sql-server stored-procedures


【解决方案1】:

我认为问题是

while @@FETCH_STATUS = 0

这将是上一次提取的结果(换句话说,是从上一次执行存储过程中提取的结果,而不是您想要的结果)。

我写游标循环的常用方法是

while 1 =1 
begin
  fetch next from c into ...
  if @@fetch_status != 0 break 
  ...
 end

【讨论】:

  • 是否会简单地将光标声明从“as”之后移动到第一个“begin”之后可能会修复它?
  • @Kevin 有很多方法可以修复它,这种“while 1=1”方法意味着您不必多次编写 fetch,我认为这更简洁,特别是如果您有很多变量要提取,就像这里一样。
  • 完美!我一直对必须写两次 fetch 感到恼火(正如你最初向我展示的那样)。虽然这些天我倾向于避免使用光标。
【解决方案2】:

没有示例数据或表结构,所以我不知道您的数据是什么样的。下面是我认为你想要的。内部查询计算每个客户的订单。外部查询对它们进行排名。

SELECT *
    , DENSE_RANK() OVER(PARTITION BY CustomerID ORDER BY OrderFrequency) AS Rnk
FROM (
    SELECT *
        , COUNT(*) OVER (PARTITION BY o.CustomerID) AS OrderFrequency
    FROM Customer_T c 
    JOIN Order_T o ON c.CustomerID = o.CustomerID
) a

【讨论】:

    猜你喜欢
    • 2011-05-16
    • 2012-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-12
    • 1970-01-01
    • 2014-02-08
    相关资源
    最近更新 更多