Boucler sur un jeu d'loggings dans SQL Server

Je suis coincé sur comment faire une boucle sur un set de lignes et save dans une variable.

Rappelez-vous, cela peut être pseudo-code parce que SQL n'est pas ma spécialité.

@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 

Comme vous pouvez le voir, je parcours les clients et dans cette boucle, j'ai besoin d'get le solde actuel et le mettre à zéro, mais je dois d'abord savoir si c'est un nombre positif ou négatif pour savoir si l'encart par user dans la table AR_Transactions doit être un nombre positif ou négatif. Pourriez-vous aider avec les pièces manquantes?

Voici une traduction directe de votre code d'origine en syntaxe SQL Server valide. Je ne peux pas parler des règles métier entourant ce que vous faites, mais notez que cette approche évite l'utilisation de sliders et utilise la fonction ABS () pour supprimer votre bloc if / else d'origine.

 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 

Vous devriez être capable de le faire dans un couple d'instructions sans l'utilisation d'un slider ou d'un autre code de procédure. Assurez-vous simplement que tout est en une seule transaction:

 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 

Bien sûr, ajoutez une gestion correcte des erreurs et assurez-vous de tester cela en premier.

En outre, j'ai légèrement modifié certains de vos noms de table et de colonne. Je ne veux pas entrer dans quelles conventions spécifiques de nommage sont meilleures que d'autres, mais au less être cohérentes. Si vous utilisez des caractères de soulignement, utilisez-les. Si vous utilisez plutôt la notation à dos de chameau, utilisez-la, mais ne les mélangez pas. Il en va de même pour les noms de tables au pluriel et au singulier.

Pour SQL 2005 et plus:

 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 

Comme il y a eu une certaine confusion, je noterai que -Deleted.Acct_Balance est tout ce dont vous avez besoin pour ramener le solde à zéro. Il annule les soldes négatifs pour insert un positif, et nie les soldes positifs pour insert un négatif.

Pour SQL 2000, vous aurez besoin de plusieurs instructions.

En règle générale, penser que vous devez effectuer des opérations basées sur des lignes dans SQL est une bonne indication que vous (ou quelqu'un d'autre) avez mal formulé le problème: c'est une odeur de code indicative d'une approche procédurale plutôt basée sur des sets.

Le pseudo-code que vous voulez est, je pense, quelque chose de ce genre:

 -- 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 

Vous searchz une fonction qui renvoie @balance si @balance> 0, else – @ balance.

ABS (@balance) ferait cela. (Sauf si vous avez besoin d'insert un littéral de string commençant par un "-" mais qui semble étrange – je suppose que la colonne Balance est un type décimal.)

Je devine au domaine d'affaires, mais il y a probablement aussi une colonne de crédit / débit que vous devriez placer selon le signe de la transaction. Dans ce cas, vous pouvez vouloir quelque chose comme:

 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 ); 

Je voudrais jeter un oeil à des sliders , mais OMI ceci est mieux fait dans la logique de l'application que dans SQL.