Loop in T-SQL, how get field value - tsql

In an SQL Server 2005 database, I have a stored procedure. I get some date in put them in a temp table. I'd like loop in this temp table and depending of the value of some fields change the value of others and make some check. I have to do this for each row.
How can I do this ?
thanks,
UPDATE1
BEGIN
SET NOCOUNT ON
--Create temp table
CREATE TABLE #MyTempTable(
id int IDENTITY(1, 1),
PriceMax int,
PriceMin int
)
-- Insert in temp table
INSERT INTO #tmpReconciliation (PriceMax, PriceMin)
SELECT PriceMax = PriceMaxProduct,
PriceMin = PriceMinProduct
FROM Products
DECLARE #RowNum int
SELECT #RowNum = Count(*) From #MyTempTable
WHILE #RowNum > 0
BEGIN
if(....)
PriceMin = 0
....
END
--Drop temp table
DROP TABLE #MyTempTable
END

I read MSDN documentation for WHILE loop and CURSOR.
For example, let's imagine your temp table is named Employee :
DECLARE #Emp_id int
DECLARE Employee_Cursor CURSOR FOR
SELECT EmployeeID
FROM Employee;
OPEN Employee_Cursor;
FETCH NEXT FROM Employee_Cursor INTO #Emp_id;
WHILE ##FETCH_STATUS = 0
BEGIN
-- Here your actions
PRINT #Emp_id
FETCH NEXT FROM Employee_Cursor INTO #Emp_id;
END;
CLOSE Employee_Cursor;
DEALLOCATE Employee_Cursor;
GO
Here I decided to print EmployeeId, but everything is possible.
Tell us what are your checks, and what your temp table looks like if you need more help.

Can't you just use a cursor and inside the cursor run an update statement??
Cursors: http://www.jackdonnell.com/articles/SQL_CURSOR.htm

Related

in if else Loop ,cannot drop the same temp table

i am using if else statement and ,i want to drop the temporary table which is created out side the inner if statement , but when i execute the statement , i get the answer as , There is already an object named '#table' in the database. ---------------------MY CODE IS LIKE enter code here
DECLARE #RowCount INT;
SET #RowCount = 1;
IF #RowCount = 1
BEGIN
IF OBJECT_ID('tempdb..#Guarantor_Details') IS NOT NULL
DROP TABLE #Guarantor_Details
SELECT DISTINCT TOP 1 GUARANTORS.GUARANTOR_CODE
INTO #Guarantor_Details
FROM GUARANTORS
WHERE ISNULL(GUARANTORS.deleted, 0) <> 1;
DECLARE #GuarantorCount INT;
SELECT #GuarantorCount = count(*)
FROM #Guarantor_Details;
IF (#GuarantorCount = 0)
DROP TABLE #Guarantor_Details
BEGIN
IF OBJECT_ID('tempdb..#Guarantor_Details') IS NOT NULL
SELECT TOP 1 CLIENT.Last_Name
INTO #Guarantor_Details
FROM CLIENT
LEFT JOIN GUARANTORS ON GUARANTORS.GUARANTOR_CODE = CLIENT.Financial_Guarantor
END
END
------------------------------------------------------------------------
You don't need to do this type of CREATE / DROP. You can (and probably should) create the table before the loop and simply either TRUNCATE TABLE or DELETE FROM the temp table when necessary to "reset" it. Just pick a datatype that fits both GUARANTOR_CODE and Last_Name.
You also don't need to do a SELECT COUNT(*) on the table when you have the ##ROWCOUNT from the INSERT operation that already has that value in it.
Essentially:
CREATE TABLE #Guarantor_Details (Value NVARCHAR(50));
WHILE (something)
BEGIN
IF (#RowCount = 1)
BEGIN
TRUNCATE TABLE #Guarantor_Details;
INSERT INTO #Guarantor_Details (Value)
SELECT DISTINCT TOP 1 GUARANTORS.GUARANTOR_CODE
FROM GUARANTORS
WHERE ISNULL(GUARANTORS.deleted, 0) <> 1;
IF (##ROWCOUNT = 0)
BEGIN
INSERT INTO #Guarantor_Details (Value)
SELECT TOP 1 CLIENT.Last_Name
FROM CLIENT
LEFT JOIN GUARANTORS
ON GUARANTORS.GUARANTOR_CODE = CLIENT.Financial_Guarantor;
END;
END;
FYI, there appear to be some logic problems in the original code:
There are BEGIN / END tags at the bottom of the IF #RowCount = 1 block that aren't associated to any IF or WHILE. This is technically ok, but usually implies something is missing.
If this code is all of the code, then the IF #RowCount = 1 doesn't work in the loop unless something sets #RowCount past the end of this outer IF block that is not shown here in the question.

How to use WITH table AS result within cursor loop to run stored procedure

How to get result in WITH table AS into CURSOR loop? I have previously asked about how to get recursive results from my table
How to read all records recursively and show by level depth TSQL
;with C as
(
definition ...
)
I have created CURSOR loop where I want to run specific stored procedure for all results in table
declare #id int, #parent int
declare cur cursor local fast_forward
for
select id, parent from C
open cur
fetch next from cur into #id, #parent
while ##fetch_status = 0
begin
exec storedProcedure #id=#id, #parent=#parent
fetch next from cur into #id, #parent
end
close cur
deallocate cur
Problem is that CURSOR doesnt know table from WITH AS result.
Invalid object name 'C'.
You can create a temp table or a table variable to hold the rows returned by you CTE query and then you use that table as the source for your cursor.
declare #T table
(
id int,
parent int
)
;with C as
(
select 1 as id, 2 as parent
)
insert into #T
select id, parent
from C
declare cur cursor for select id, parent from #T

Sql Server Trigger between 2 databases

I have 2 databases. One, named Test, has a table named Vehicles. Another, named Test2 has a table named Clients.
When I insert a new record on the Vehicles table in Test, I need to update the NumVehicles field on the Clients table in Test2.
Is this possible using triggers?
You need something like
USE Test;
GO
CREATE TRIGGER afterVehicleInsert ON Vehicles AFTER INSERT
AS
BEGIN
IF ##rowcount = 0 RETURN;
UPDATE Test2.[schema_name(default schema is dbo)].Clients
SET NumVehicles = NumVehicles +1 -- or whatever it should be
FROM Test2.[schema_name(default schema is dbo)].Clients c
INNER JOIN inserted i ON ([your join condition])
END;
GO
The only difference between updating the table in current and another db is that you need to refer a "remote" table using [db_name].[schema_name].[table_name]
This is working code is given below
USE BioStar;
GO
CREATE TRIGGER trgAfterInsertnew ON [dbo].[TB_EVENT_LOG]
FOR INSERT
AS
declare #nDateTime int;
declare #nReaderIdn int;
declare #nEventIdn int;
declare #nUserID int;
declare #nIsLog smallint;
declare #nTNAEvent smallint;
declare #nIsUseTA smallint;
declare #nType smallint;
select #nDateTime=i.nDateTime from inserted i;
select #nDateTime=i.nReaderIdn from inserted i;
select #nEventIdn=i.nEventIdn from inserted i;
select #nUserID=i.nUserID from inserted i;
select #nIsLog=i.nIsLog from inserted i;
select #nTNAEvent=i.nTNAEvent from inserted i;
select #nIsUseTA=i.nIsUseTA from inserted i;
select #nType=i.nType from inserted i;
insert into [HRM].dbo.Device_Data
(nDateTime,nReaderIdn,nEventIdn,nUserID,nIsLog,nTNAEvent,nIsUseTA,nType)
values(#nDateTime,#nDateTime,#nEventIdn,#nUserID,#nIsLog,#nTNAEvent,#nIsUseTA,#nType);
--set #audit_action='Inserted Record -- After Insert Trigger.';
PRINT 'AFTER DELETE TRIGGER fired.'
GO

Union select statements within the while loop T-SQL

I'm trying to use cursors to dynamically produce a result set. following is the code
DECLARE # MilestoneName VARCHAR(100),
#MilestoneSts VARCHAR(100),
#ProjectPre VARCHAR(10),
#ProjectID VARCHAR(10),
#Center VARCHAR(20),
#CenterPre VARCHAR(20),
#Source VARCHAR(20),
#Actual INT;
SET #MilestoneName = null;
SET #MilestoneSts = null;
SET #ProjectPre = null;
SET #CenterPre = null;
DECLARE s_cursor CURSOR FOR
SELECT ProjectID, Center, Source, Actual
FROM #MILESTONE
OPEN s_cursor
FETCH NEXT FROM s_cursor INTO #ProjectID, #Center, #Source, #Actual
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT ##FETCH_STATUS sts, #ProjectID PID, #Center Center, #Source Source, #Actual Actual
FETCH NEXT FROM s_cursor INTO #ProjectID, #Center, #Source, #Actual
END
CLOSE s_cursor
DEALLOCATE s_cursor
However using that I'm able to produce 79 results of single rows but I want to union all those rows into one result.. any possible solution will be highly appreciated..
just checking, why are you using a cursor for this?
This sproc could be replaced by just saying
SELECT ProjectID, Center, Source, Actual
FROM #MILESTONE
But maybe I'm missing somehting here?
If there's logic you left out in your code look at this post: Multi-statement Table Valued Function vs Inline Table Valued Function
GJ

Array-like access to variables in T-SQL

In my stored procedure I have multiple similar variables #V1, #V2 ... #V20 (let's say 20 of them) FETCHED from a record. How would I use dynamic SQL to make 20 calls to another stored procedure using those variables as parameters?
Of course #V[i] syntax is incorrect, but it expresses the intent
fetch next from maincursor into #status, #V1, #V2, ...
while #i<21
begin
-- ??? execute sp_executesql 'SecondSP', '#myParam int', #myParam=#V[i]
-- or
-- ??? execute SecondSP #V[i]
set #i = #i+1
end
As others have said, set up a temporary table, insert the values that you need into it. Then "iterate" through it executing the necessary SQL from those values. This will allow you to have 0 to MANY values to be executed, so you don't have to set up a variable for each.
The following is a complete sample of how you may go about doing that without cursors.
SET NOCOUNT ON
DECLARE #dict TABLE (
id INT IDENTITY(1,1), -- a unique identity column for reference later
value VARCHAR(50), -- your parameter value to be passed into the procedure
executed BIT -- BIT to mark a record as being executed later
)
-- INSERT YOUR VALUES INTO #dict HERE
-- Set executed to 0 (so that the execution process will pick it up later)
-- This may be a SELECT statement into another table in your database to load the values into #dict
INSERT #dict
SELECT 'V1Value', 0 UNION ALL
SELECT 'V2Value', 0
DECLARE #currentid INT
DECLARE #currentvalue VARCHAR(50)
WHILE EXISTS(SELECT * FROM #dict WHERE executed = 0)
BEGIN
-- Get the next record to execute
SELECT
TOP 1 #currentid = id
FROM #dict
WHERE executed = 0
-- Get the parameter value
SELECT #currentvalue = value
FROM #dict
WHERE id = #currentid
-- EXECUTE THE SQL HERE
--sp_executesql 'SecondSP', '#myParam int', #myParam =
PRINT 'SecondSP ' + '#myParam int ' + '#myParam = ' + #currentvalue
-- Mark record as having been executed
UPDATE d
SET executed = 1
FROM #dict d
WHERE id = #currentid
END
Use a #TempTable
if you are at SQL Server 2005 you can create a #TempTable in the parent stored procedure, and it is available in the child stored procedure that it calls.
CREATE TABLE #TempTable
(col1 datatype
,col2 datatype
,col3 datatype
)
INSERT INTO #TempTable
(col1, col2, col3)
SELECT
col1, col2, col3
FROM ...
EXEC #ReturnCode=YourOtherProcedure
within the other procedure, you have access to #TempTable to select, delete, etc...
make that child procedure work on a set of data not on one element at a time
remember, in SQL, loops suck performance away!
Why not just use the table variable instead, and then just loop through the table getting each value.
Basically treat each row in a table as your array cell, with a table that has one column.
Just a thought. :)
This seems like an odd request - will you always have a fixed set of variables? What if the number changes from 20 to 21, and so on, are you constantly going to have to be declaring new variables?
Is it possible, instead of retrieving the values into separate variables, to return them each as individual rows and just loop through them in a cursor?
If not, and you have to use the individual variables as explained, here's one solution:
declare #V1 nvarchar(100)
set #V1 = 'hi'
declare #V2 nvarchar(100)
set #V2 = 'bye'
declare #V3 nvarchar(100)
set #V3 = 'test3'
declare #V4 nvarchar(100)
set #V4 = 'test4'
declare #V5 nvarchar(100)
set #V5 = 'end'
declare aCursor cursor for
select #V1
union select #V2 union select #V3
union select #V4 union select #V5
open aCursor
declare #V nvarchar(100)
fetch next from aCursor into #V
while ##FETCH_STATUS = 0
begin
exec TestParam #V
fetch next from aCursor into #V
end
close aCursor
deallocate aCursor
I don't really like this solution, it seems messy and unscalable. Also, as a side note - the way you phrased your question seems to be asking if there are arrays in T-SQL. By default there aren't, although a quick search on google can point you in the direction of workarounds for this if you absolutely need them.