Assign result of SELECT * statement to variable SQL SERVER - sql-server

I have a table with 700 rows. What I want to do is, to execute `select * from table_name' query on it and whatever result I will get want to store it in a variable and after that is done, want to traverse through each record for processing purpose? How do I achieve it? Any help??
Thanks in adv,
-saurabh

you want something which is called cursors
Cursors
You use a cursor to fetch rows returned by a query. You retrieve the rows into the cursor using a query and then fetch the rows one at a time from the cursor.
Steps
Declare variables to store the column values for a row.
Declare the cursor, which contains a query.
Open the cursor.
Fetch the rows from the cursor one at a time and store the column values in the variables declared in Step 1. You would then do something with those variables; such as display them on the screen, use them in a calculation, and so on.
Close the cursor.  
hopefully this might help you cursor

here is an example I use to start with
USE pubs
GO
-- Declare the variables to store the values returned by FETCH.
DECLARE #au_lname varchar(40), #au_fname varchar(20)
DECLARE authors_cursor CURSOR FOR
SELECT au_lname, au_fname FROM authors
--WHERE au_lname LIKE 'B%'
ORDER BY au_lname, au_fname
OPEN authors_cursor
-- Perform the first fetch and store the values in variables.
-- Note: The variables are in the same order as the columns
-- in the SELECT statement.
FETCH NEXT FROM authors_cursor
INTO #au_lname, #au_fname
-- Check ##FETCH_STATUS to see if there are any more rows to fetch.
WHILE ##FETCH_STATUS = 0
BEGIN
-- Concatenate and display the current values in the variables.
PRINT #au_fname
-- This is executed as long as the previous fetch succeeds.
FETCH NEXT FROM authors_cursor
INTO #au_lname, #au_fname
END
CLOSE authors_cursor
DEALLOCATE authors_cursor
GO

Related

Cursor is repeating first record forever

can someone tell me what is wrong with my code please. I'm simply trying to loop through a table with 2 records and get it to return 2 records. But as you may see in the image below, it keeps just repeating the first record (forever, until I hit cancel). Thank you
SET NOCOUNT ON -- Improves performance by not returning number of rows affected
--General Variables
DECLARE #ImportGUID uniqueidentifier =NEWID() -- Declares and sets a new Unique number. Can be used to remove records at a later stage
--Cursor Variables
DECLARE #FirstNameVariable varchar(50)
DECLARE #SurnameVariable varchar(50)
PRINT 'Starting import ' + CONVERT(varchar(255), #ImportGUID); --just display this on the screen
--Declare the first cursor which will loop through a table collecting data
DECLARE NewPersonTableImportCursor CURSOR FOR
SELECT Firstname, Surname
from dbo.A_NewPersonTable
--Open NewPersonTableImportCursor
OPEN NewPersonTableImportCursor
--Start looping through the data and updating the cursor variables with data from this cursor
FETCH NEXT FROM NewPersonTableImportCursor INTO #FirstNameVariable, #SurnameVariable
WHILE ##FETCH_STATUS=0 --Fetch Status 0 means successfull so only proceed on those rows from source table that were successfull
BEGIN
PRINT #FirstNameVariable;
END
CLOSE NewPersonTableImportCursor
Add FETCH NEXT FROM NewPersonTableImportCursor INTO #FirstNameVariable, #SurnameVariable before the end of the loop to get the next record

How to create a SQL function which splits comma separated value?

I want to create a function in SQL Server which takes a comma separated string a parameter, splits it and returns one value at a time. The basic idea here is to call that function from a query. Something like this.
CREATE FUNCTION SPLIT_VALUE(#IN_CSV)
RETURN VARCHAR AS
-- LOGIC TO RETURN A SINGLE VALUE FROM CSV
END
I want to call this function from a stored procedure.
CREATE PROCEDURE DEMO_PROC #IN_CSV VARCHAR(5000), #OUT VARCHAR(5000) OUTPUT AS
BEGIN
SELECT #OUT= CONCAT(A.VALUE1,B.VALUE2) FROM TABLE1 A INNER JOIN TABLE2 B ON A.ID=B.ID WHERE A.ID
IN(--CALL THE FUNCTION AND GET ONE VALUE);
END;
I have to create a loop or cursor to point to a particular value every time. Is this practically possible to? If yes then how can I do that?
Like I mention, you'll have to use a CURSOR to do this, however, the fact you want to do it this way infers a (large) design flaw:
DECLARE #value varchar(8000)
DECLARE Delimited_Values CURSOR FAST_FORWARD
FOR
SELECT [value]
FROM STRING_SPLIT('a,b,c,d,e',',')
OPEN Delimited_Values;
FETCH NEXT FROM Delimited_Values
INTO #value;
WHILE ##FETCH_STATUS = 0 BEGIN
SELECT #value; --Do your stuff here
FETCH NEXT FROM Delimited_Values
INTO #value;
END;
CLOSE Delimited_Values;
DEALLOCATE Delimited_Values;

SQL Server - Triggers & Cursors - For Each Inserted Row, Update an Associated Value on Another Table

For a homework assignment, I'm trying to build a trigger that allows for multiple inserts/updates/deletes by utilizing a cursor. We have to use a cursor in order to practice the syntax. We know that there are very few practical scenarios for cursors in a production environment.
Here's what I'm trying to accomplish:
For each row inserted into the TAL_ORDER_LINE table, update the ON_HAND value in the TAL_ITEM table by subtracting the NUM_ORDERED value from the stored ON_HAND value.
Table Structure:
Current Query:
ALTER TRIGGER update_on_hand
ON TAL_ORDER_LINE
AFTER INSERT AS
DECLARE #vItemNum as char
DECLARE #vNumOrdered as int
DECLARE new_order CURSOR FOR
SELECT ITEM_NUM, NUM_ORDERED
FROM inserted
OPEN new_order;
FETCH NEXT FROM new_order INTO #vItemNum, #vNumOrdered;
WHILE ##FETCH_STATUS=0
BEGIN
UPDATE TAL_ITEM
SET ON_HAND = ON_HAND - #vNumOrdered
WHERE ITEM_NUM = #vItemNum
FETCH NEXT FROM new_order INTO #vItemNum, #vNumOrdered;
END
CLOSE new_order
DEALLOCATE new_order
My Insert Query:
INSERT INTO TAL_ORDER_LINE (ORDER_NUM, ITEM_NUM, NUM_ORDERED, QUOTED_PRICE)
VALUES (51626, 'KL78', 10, 10.95), (51626, 'DR67', 10, 29.95)
It runs successfully, but does not affect the ON_HAND value. I think the biggest problem is that I'm struggling to understand cursor syntax, especially the INTO clause in the FETCH statement and how data from the 'inserted' table is passed into the cursor. What do I need to know to get this to work? Thanks in advance!
Your problem is likely due to this:
DECLARE #vItemNum as char
it is HIGHLY unlikely that the ItemNum column is a single character. For future reference, you should always verify that you variable definitions are consistent with the values you expect to store in them. And as has been hinted - you will get better answers by posting a complete script rather than a picture.
Big question,how you gonna debug ?
Is On_Hand col NULL , then do this isnull(on_Hand,0)
DECLARE #vItemNum as char
DECLARE #vNumOrdered as int
DECLARE new_order CURSOR FOR
SELECT ITEM_NUM, NUM_ORDERED
FROM TAL_ORDER_LINE
OPEN new_order;
FETCH NEXT FROM new_order INTO #vItemNum, #vNumOrdered;
WHILE ##FETCH_STATUS=0
BEGIN
--UPDATE TAL_ITEM
--SET ON_HAND = ON_HAND - #vNumOrdered
--WHERE ITEM_NUM = #vItemNum
print #vItemNum
print vNumOrdered
FETCH NEXT FROM new_order INTO #vItemNum, #vNumOrdered;
END
CLOSE new_order
DEALLOCATE new_order
Try this :
ALTER TRIGGER update_on_hand ON TAL_ORDER_LINE
FOR INSERT AS
BEGIN
UPDATE TI
SET TI.ON_HAND = TI.ON_HAND - I.NUM_ORDERED
TAL_ITEM TI INNER JOIN
INSERTED I ON I.ITEM_NUM = TI.ITEM_NUM
END
Changed Trigger to FOR INSERT Trigger
Removed Cursor
Note: NOT Tested. ( If you post the sql scripts for create table + sample inserts I can give it a try )

Table Variable inside cursor, strange behaviour - SQL Server

I observed a strange thing inside a stored procedure with select on table variables. It always returns the value (on subsequent iterations) that was fetched in the first iteration of cursor. Here is some sample code that proves this.
DECLARE #id AS INT;
DECLARE #outid AS INT;
DECLARE sub_cursor CURSOR FAST_FORWARD
FOR SELECT [TestColumn]
FROM testtable1;
OPEN sub_cursor;
FETCH NEXT FROM sub_cursor INTO #id;
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #Log TABLE (LogId BIGINT NOT NULL);
PRINT 'id: ' + CONVERT (VARCHAR (10), #id);
INSERT INTO Testtable2 (TestColumn)
OUTPUT inserted.[TestColumn] INTO #Log
VALUES (#id);
IF ##ERROR = 0
BEGIN
SELECT TOP 1 #outid = LogId
FROM #Log;
PRINT 'Outid: ' + CONVERT (VARCHAR (10), #outid);
INSERT INTO [dbo].[TestTable3] ([TestColumn])
VALUES (#outid);
END
FETCH NEXT FROM sub_cursor INTO #id;
END
CLOSE sub_cursor;
DEALLOCATE sub_cursor;
However, while I was posting the code on SO and tried various combinations, I observed that removing top from the below line, gives me the right values out of table variable inside a cursor.
SELECT TOP 1 #outid = LogId FROM #Log;
which would make it like this
SELECT #outid = LogId FROM #Log;
I am not sure what is happening here. I thought TOP 1 on table variable should work, thinking that a new table is created on every iteration of the loop. Can someone throw light on the table variable scoping and lifetime.
Update: I have the solution to circumvent the strange behavior here.
As a solution, I have declared the table at the top before the loop and deleting all rows at the beginning of the loop.
There are numerous things a bit off with this code.
First off, you roll back your embedded transaction on error, but I never see you commit it on success. As written, this will leak a transaction, which could cause major issues for you in the following code.
What might be confusing you about the #Log table situation is that SQL Server doesn't use the same variable scoping and lifetime rules as C++ or other standard programming languages. Even when declaring your table variable in the cursor block you will only get a single #Log table which then lives for the remainder of the batch, and which gets multiple rows inserted into it.
As a result, your use of TOP 1 is not really meaningful, since there's no ORDER BY clause to impose any sort of deterministic ordering on the table. Without that, you get whatever order SQL Server sees fit to give you, which in this case appears to be the insertion order, giving you the first inserted element of that log table every time you run the SELECT.
If you truly want only the last ID value, you will need to provide some real ordering criterion for your #Log table -- some form of autonumber or date field alongside the data column that can be used to provide the proper ordering for what you want to do.

Delete row from cursor source SQL Server

I have a SQL Server 2005 cursor operating over a table variable called #workingSet.
Some times rows can be related and in this case I process the row I have fetched and the related rows at the same time. I then remove the related records from #workingset as I don't need to process then in the loop.
In a #workingSet with 7 rows, the first two are related so when I process 1 I also process 2. I remove row 2 from the cursor source (#workingSet) and then fetch next. The problem is it returns the second row in #workingset (the one I deleted on the previous iteration).
I was of the impression that this could be done i.e. deleting an item from a source that a cursor operates on and it will honour the delete in subsequent fetches.
The answer appears to be that the table variable that is being used as the source of the cursor needs to have a primary key. I've added this and all works correctly.
Not massively familiar with cursors but from a quick test this end you need to avoid declaring the cursor with the STATIC or KEYSET options then the changes to the underlying table are reflected in the cursor.
SET NOCOUNT ON;
DECLARE #WorkingTable TABLE(C int)
INSERT INTO #WorkingTable VALUES (1),(2),(3)
DECLARE #C int
DECLARE wt_cursor CURSOR
DYNAMIC /*Or left blank but not STATIC or KEYSET*/
FOR
SELECT C
FROM #WorkingTable
OPEN wt_cursor;
FETCH NEXT FROM wt_cursor
INTO #C
DELETE FROM #WorkingTable
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #C;
FETCH NEXT FROM wt_cursor
INTO #C;
END
CLOSE wt_cursor;
DEALLOCATE wt_cursor;

Resources