Цикл по набору записей в SQL Server - PullRequest
4 голосов
/ 23 мая 2011

Я застрял на том, как перебрать набор строк и сохранить в переменной.

Имейте в виду, это может быть псевдокод, потому что 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 ]

3 голосов
/ 23 мая 2011

Вы должны быть в состоянии сделать это в паре операторов без использования курсора или другого процедурного кода. Просто убедитесь, что это все в одной транзакции:

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

Конечно, добавьте правильную обработку ошибок и обязательно проверьте это в первую очередь.

Кроме того, я немного изменил некоторые имена ваших таблиц и столбцов. Я не хочу вдаваться в то, какие конкретные соглашения об именах лучше других, но на минимум будьте последовательны. Если вы собираетесь использовать подчеркивание, используйте их. Если вы собираетесь использовать нотацию верблюда, используйте ее, но не смешивайте их. То же самое относится к именам таблиц во множественном числе и в единственном числе.

2 голосов
/ 24 мая 2011

Для 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 вам потребуется несколько операторов.

1 голос
/ 23 мая 2011

Как правило, мысль о том, что вам нужно выполнять операции на основе строк в 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
0 голосов
/ 24 мая 2011

Вот прямой перевод вашего исходного кода в действительный синтаксис 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
0 голосов
/ 23 мая 2011

Вы ищете функцию, которая возвращает @balance, если @balance> 0, иначе -@balance.

ABS (@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 ); 
0 голосов
/ 23 мая 2011

Я бы взглянул на курсоры , однако IMO это лучше сделать в логике приложения, чем в SQL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...