循环SQL Server中的记录集

时间:2011-05-23 18:45:59

标签: sql sql-server sql-server-2008 loops

我坚持如何遍历行集并保存在变量中。

请注意,这可能是伪代码,因为SQL不是我的专长。

 @all_customers = select CustNum from [crrsql].[dbo].[Customer];
 some loop(@all_customers as user)
 //I need to find out what the Acct_balance field is and either subtract or add to bring all the balances to 0
    @balance = select Acct_balance from [crrsql].[dbo].[Customer] where CustNum = user;
    if @balance > 0 
      update [crrsql].[dbo].[Customer] set Acct_balance = 0;
      INSERT INTO [crrsql].[dbo].[AR_Transactions] (cashier_ID, CustNum, Balance) VALUES (100199, user, @balance); 
    else
      update [crrsql].[dbo].[Customer] set Acct_balance = 0;
      INSERT INTO [crrsql].[dbo].[AR_Transactions] (cashier_ID, CustNum, Balance) VALUES (100199, user, "-" + @balance); 
    end
 end loop

正如您所看到的,我正在循环客户并在该循环中我需要获得当前余额并将其设置为零,但首先我需要找出它是正数还是负数才能够找出如果AR_Transactions表中的每个用户的插入需要是正数或负数。你可以帮忙找到丢失的部分吗?

6 个答案:

答案 0 :(得分:3)

您应该可以在几个语句中执行此操作,而无需使用游标或其他过程代码。只需确保它在一个交易中完成:

BEGIN TRANSACTION

INSERT INTO crrsql.dbo.AR_Transactions (
    cashier_id,
    cust_num,
    balance,
    transaction_date)
SELECT
    100199,
    cust_num,
    -acct_balance,
    DATEADD(MINUTE, -30, current_date)
FROM crrsql.dbo.Customers
WHERE acct_balance <> 0

UPDATE crrsql.dbo.Customers SET acct_balance = 0 WHERE acct_balance <> 0

COMMIT TRANSACTION

当然,添加正确的错误处理并确保首先测试它。

另外,我稍微修改了一些表名和列名。我不想让哪些特定的命名约定比其他命名约定更好,但至少是一致的。如果您要使用下划线,请使用它们。如果您打算使用驼峰符号然后使用它,但不要混用它们。复数与单数表名称相同。

答案 1 :(得分:2)

对于SQL 2005及更高版本:

UPDATE C
SET C.Acct_Balance = 0
OUTPUT 100199, Inserted.CustNum, -Deleted.Acct_Balance, DateAdd(Minute, -30, GetDate())
INTO crrsql.dbo.AR_Transactions (Cashier_ID, CustNum, Balance, Transaction_Date)
FROM crrsql.dbo.Customer C
WHERE C.Acct_Balance <> 0

由于存在一些混淆,我会注意到-Deleted.Acct_Balance 是您需要的全部以使余额为零。它否定负平衡以插入正数,并否定正平衡以插入负数。

对于SQL 2000,您需要多个语句。

答案 2 :(得分:1)

作为一般规则,认为你需要在SQL中进行基于行的操作是一个很好的迹象,表明你(或其他人)错误地构建了问题:它是一种代码气味,表示程序性而非基于集合的思维

我想,你想要的伪代码是这样的:

-- Create a temporary table. A table starting with # is a temporary. It will be
-- automatically dropped when the session ends. If two sessions creates temp
-- tables with the same name, at the same time, they will still get one table each.
create table #work
(
  CustNum int ,
  Balance money ,
)

insert #work ( CustNum , Balance )
select CustNum , Balance
from Customer
where Balance != 0

begin transaction

insert dbo.AR_Transactions (cashier_ID, CustNum, Balance)
select cashier_ID = 100199 ,
       user       = CustNum ,
       adjustment = case sign(@balance) -- should always be +1 or -1
                    when  1 then @balance -- positive balance
                    when -1 then -@balace -- negative balance
                    end 

update Customer set balance = 0
from Customer c
join #work    w on w.CustNum = c.CustNum

commit transaction

-- Manual tidying up if the connection might be kept open.
drop table #work

答案 3 :(得分:0)

你正在寻找一个函数,如果@ balance&gt; 0,则返回@balance,否则 - @ balance。

ABS(@balance)会这样做。 (除非你需要插入一个以“ - ”开头的字符串文字,但这看起来很奇怪 - 我假设Balance列是一个十进制类型。)

我猜测业务领域,但可能还有一个信用/借记列,您需要根据交易的标志进行设置。在这种情况下,您可能需要以下内容:

INSERT INTO [crrsql].[dbo].[AR_Transactions] (cashier_ID, CustNum, Balance, CR_DR ) VALUES (100199, user, ABS(@balance), CASE WHEN @balance > 0 THEN 'CR' ELSE 'DR' END ); 

答案 4 :(得分:0)

以下是将原始代码直接转换为有效的SQL Server语法。我不能谈论你正在做什么的业务规则,但请注意,这种方法避免使用游标,并使用ABS()函数取消原来的if / else块。

declare @all_customers as table(
  customernumber int
);

/*
--you can insert dummy data for testing purposes like so:
insert into @all_customers
select 5, 1
union
select 2, 1
--*/


while (0 < (select count(*) from @all_customers)) begin
  declare @current_customer int = (select top 1 customernumber from @all_customers);

  declare @balance money = (select acct_balance from [crrsql].[dbo].[Customer] where CustNum = @current_customer);
  update [crrsql].[dbo].[Customer] set Acct_balance = 0;
  INSERT INTO [crrsql].[dbo].[AR_Transactions] (cashier_ID, CustNum, Balance) VALUES (100199, user, abs(@balance)); 

  delete @all_customers where customernumber = @current_customer;
end

答案 5 :(得分:-1)

我会看看cursors,但IMO在应用程序逻辑中比在SQL中做得更好。