I am having problems with the following code:
/* Cursor */
DECLARE #RelationCursor CURSOR
SET #RelationCursor = (SELECT [fms].[dbo].[Relation].[RELATIONCODE], [fms].[dbo].[Relation].[COMPANYNAME] INTO #RelationCode, #CompanyName FROM [fms].[dbo].[Relation])
OPEN #RelationCursor
FETCH NEXT FROM #RelationCursor INTO #RelationCode, #CompanyName
WHILE ##FETCH_STATUS = 0
BEGIN
print(#RelationCode)
print(#CompanyName)
FETCH NEXT FROM #RelationCursor INTO #RelationCode, #CompanyName
END
CLOSE #RelationCursor
I am trying to get RelationCode and Companyname into #RelationCode and #Companyname so I can use them in the cursor loop. But I get an error in the SELECT query:
Msg 156, Level 15, State 1, Procedure spLoadProfits, Line 21
Incorrect syntax near the keyword 'INTO'.
But the query seems completely fine to me and I can't seem to figure out the problem about this. Does anyone have an idea on how to fix this?
A cursor name should not start with #, and also you need to deallocate the cursor when you are done with it.
Try this instead:
DECLARE #RelationCode int, -- I guessed the data type, change if needed
#CompanyName varchar(100) -- I guessed the data type, change if needed
DECLARE RelationCursor CURSOR FOR
SELECT [fms].[dbo].[Relation].[RELATIONCODE], [fms].[dbo].[Relation].[COMPANYNAME]
FROM [fms].[dbo].[Relation]
OPEN RelationCursor
FETCH NEXT FROM RelationCursor INTO #RelationCode, #CompanyName
WHILE ##FETCH_STATUS = 0
BEGIN
print(#RelationCode)
print(#CompanyName)
FETCH NEXT FROM RelationCursor INTO #RelationCode, #CompanyName
END
CLOSE RelationCursor
DEALLOCATE RelationCursor;
Related
Im trying to process rows using CURSOR and write values for each row to a temporary table. This works if I use the FOR loop e. g. FOR myLoop AS myCursor CURSOR FOR ... but I want to use the cursor as documented for T-SQL and as soon as I uncomment the line where I try to declare the temporary table I get a cryptic error message:
Could not execute statement.
Syntax error near 'BEGIN' on line 10 (Watcom SQL)
SQLCODE=-131, ODBC 3 State="42000"
Line 10
Also the 'AS' in the column definition in the temp table declaration is not the problem! The three lines that are commented out can be run without any problem if the other lines are removed.
Any Ideas?
BEGIN
-- DECLARE LOCAL TEMPORARY TABLE tempTable (iValue AS INTEGER);
DECLARE #iValue INT;
DECLARE myCursor CURSOR FOR SELECT ItemValue FROM ListItems;
OPEN myCursor;
FETCH NEXT myCursor INTO #iValue;
WHILE (##FETCH_STATUS = 0) BEGIN
FETCH NEXT myCursor INTO #iValue
END;
CLOSE myCursor;
DEALLOCATE myCursor;
-- SELECT iValue AS [Values] FROM tempTable;
-- DROP TABLE IF EXISTS tempTable;
END
Thanks
I have a problem with this stored procedure.
Parameters from my application are well defined, but in this procedure, when I am trying to insert a row into table Image, it insert only the first row from #xmlImages and I sent two values. I appreciate any help!
CREATE PROCEDURE sp_AddExplanationAndImage
#Text NVARCHAR(MAX) = NULL,
#ID INT = 0
#ListOfImages NVARCHAR(MAX) = NULL
AS
BEGIN
INSERT INTO dbo.Explanation (ID, Text)
VALUES (#ID, #Text)
DECLARE #xmlImages xml
SET #xmlImages = CAST(#ListOfImages AS xml)
DECLARE #ImageExtension NVARCHAR(MAX)
DECLARE #Name NVARCHAR(MAX)
DECLARE #Content VARBINARY(MAX)
IF (#ListOfImages IS NOT NULL)
BEGIN
DECLARE cursor cursor for--local fast_forward for
SELECT
s.x.value('(Image/Extension)[1]', 'nvarchar(max)'),
s.x.value('(Image/Name)[1]', 'nvarchar(max)'),
s.x.value('(Image/Content)[1]', 'varbinary(max)')
FROM
#xmlImages.nodes('Images') AS s(x)
OPEN CURSOR
FETCH NEXT FROM cursor INTO #ImageExtension, #Name, #Content
WHILE ##FETCH_STATUS = 0
BEGIN
IF ##fetch_status <> 0
BREAK
INSERT INTO dbo.Image (Extension, Name, Content)
SELECT #ImageExtension, #Name, #Content
FETCH NEXT FROM cursorSlike INTO #ImageExtension, #Name, #Content
END
CLOSE cursor
DEALLOCATE cursor
END
The fetch next from inside the WHILE block does not reference the cursor that you're looping through. You named your cursor cursor (I recommend using a more descriptive name BTW) but you're fetching next from cursorSlike.
But I'm not sure you need the loop in the first place (in general, you should avoid loops in SQL Server unless there's no other way to accomplish the task). I haven't done a lot with XML in SQL Server but have you tried this?
INSERT INTO dbo.Image(Extension,Name,Content)
SELECT
s.x.value('(Image/Extension)[1]','nvarchar(max)'),
s.x.value('(Image/Name)[1]','nvarchar(max)'),
s.x.value('(Image/Content)[1]','varbinary(max)')
FROM #xmlImages.nodes('Images')AS s(x)
According to your sample data. you need to get Images/Image nodes. And you dont need to use cursor.
INSERT INTO dbo.Image(Extension,Name,Content)
SELECT
s.x.value('(Extension)[1]','nvarchar(max)'),
s.x.value('(Name)[1]','nvarchar(max)'),
s.x.value('(Content)[1]','nvarchar(max)')
FROM #xmlImages.nodes('Images/Image')AS s(x)
I wonder whether cursor for query with #variable parameter can be re-used (CLOSE + OPEN) when value of the #variable changes. To me it looks that it always needs CLOSE + DEALLOCATE + DECLARE + OPEN to take new value of the #variable into effect. Perhaps no big deal, but I wanted to know whether DEALLOCATE + DECLARE can be left out between uses.
Here you have complete simple example to try it out:
DECLARE #ta TABLE (a int);
INSERT INTO #ta (a) VALUES (1),(2),(4),(8),(16),(32),(64);
---------
DECLARE #current_a int;
DECLARE #threshold int = 12;
DECLARE crs1 CURSOR FOR SELECT a FROM #ta WHERE a < #threshold;
--- first cursor use
OPEN crs1;
FETCH NEXT FROM crs1 INTO #current_a;
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #threshold, #current_a
FETCH NEXT FROM crs1 INTO #current_a;
END;
CLOSE crs1;
DEALLOCATE crs1; -- can this be left out?
SET #threshold = 3;
DECLARE crs1 CURSOR FOR SELECT a FROM #ta WHERE a < #threshold; -- can this be left out?
--- second cursor use
OPEN crs1;
FETCH NEXT FROM crs1 INTO #current_a;
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #threshold, #current_a
FETCH NEXT FROM crs1 INTO #current_a;
END;
CLOSE crs1;
DEALLOCATE crs1;
This was linearized example, but the question applies also to nested cursors when outer cursor changes the query parameter of inner cursor.
One way is to use cursor variable:
DECLARE
{
{ #local_variable [AS] data_type | [ = value ] }
| { #cursor_variable_name CURSOR }
#cursor_variable_name
Is the name of a cursor variable. Cursor variable names must begin with an at (#) sign and conform to the rules for identifiers.
CURSOR
Specifies that the variable is a local cursor variable.
A cursor variable:
Can be the target of either a cursor type or another cursor variable. For more information, see SET #local_variable.
Can be referenced as the target of an output cursor parameter in an EXECUTE statement if the cursor variable does not have a cursor
currently assigned to it.
Should be regarded as a pointer to the cursor.
DECLARE crs1 CURSOR FOR SELECT a FROM #ta WHERE a < #threshold;
-- could be changed to
DECLARE #crs1 CURSOR;
SET #crs1 = CURSOR FOR SELECT a FROM #ta WHERE a < #threshold;
LiveDemo
Below is a portion of a stored procedure I'm working on (the snippet can be executed) which returns the error
The multi-part identifier "CountCursor.ID" could not be bound.
But why?
DECLARE #MANTECCount int
DECLARE #ThirdPartyCount int
DECLARE #MemberNo nchar(4)
SET #MANTECCount = 0
SET #ThirdPartyCount = 0
SET #MemberNo = NULL
DECLARE CountCursor CURSOR FOR
SELECT ID
FROM CIF
OPEN CountCursor
FETCH NEXT FROM CountCursor
WHILE ##FETCH_STATUS = 0
BEGIN
SET #MemberNo = CountCursor.ID
FETCH NEXT FROM CountCursor;
END;
CLOSE CountCursor;
DEALLOCATE CountCursor;
You need to assign the fetched value from Cursor(CountCursor) into a variable to use it inside Cursor. More info on Cursor's can be found here
Declare #id int
......
FETCH NEXT FROM CountCursor into #id
WHILE ##FETCH_STATUS = 0
BEGIN
SET #MemberNo = #id
FETCH NEXT FROM CountCursor into #id;
END;
....
Note: Cursor's can have awful performance. If you add the original code we can try and change it to SET Based Approach code.
You need to fetch the value into something. At first, I was wondering about the code structure, then I realized that Python (and probably other languages) treat cursors the same way.
In any case, you can put the value directly into #MemberNo:
DECLARE #MANTECCount int;
DECLARE #ThirdPartyCount int;
DECLARE #MemberNo nchar(4);
SET #MANTECCount = 0;
SET #ThirdPartyCount = 0;
SET #MemberNo = NULL;
DECLARE CountCursor CURSOR FOR
SELECT ID
FROM CIF;
OPEN CountCursor;
FETCH NEXT FROM CountCursor INTO #MemberNo;
WHILE ##FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM CountCursor INTO #MemberNo;
END;
CLOSE CountCursor;
DEALLOCATE CountCursor;
GO
I'm not sure what the code should be doing. Presumably, you have more interesting code than this.
Hi I have a procedure in MS SQL Server 2012, in which I am performing some insertions and updating but in some piece of that procedure, I am using cursor for looping in insertion.
Can some one please help me doing that looping insertion without using cursor?
Complete code is below
(
#TerritoryName varchar(200),
#TerritoryDescription varchar(2000),
#TerritoryID int,
#CountyIDs varchar(500),
#ZipCodeIDs varchar(500)
)
AS
BEGIN
Declare #countyid int,#zipcodeid int,#Target_GeographyTypeID int;
DECLARE #t TABLE(idx int primary key identity,id int)
DECLARE #tzip TABLE(idx int primary key identity,id int)
INSERT INTO #t
SELECT item from fn_split(#CountyIDs,',')
INSERT INTO #tzip
SELECT item from fn_split(#ZipCodeIDs,',')
IF(#TerritoryID < 1)
BEGIN
INSERT INTO Territories(TerritoryName,TerritoryDescription,Active,CreatedDate)
VALUES(#TerritoryName,#TerritoryDescription,1,Getdate())
SET #TerritoryID= ##identity
END
ELSE
BEGIN
UPDATE Territories
SET TerritoryName=#TerritoryName,
TerritoryDescription=#TerritoryDescription
WHERE TerritoryID=#TerritoryID
END
SELECT #Target_GeographyTypeID=GeographyTypeId from GeoGraphyTypes
WHERE GeographyTypeName='County'
DELETE from Territory_mapping
WHERE TerritoryID=#TerritoryID
DECLARE db_cursor CURSOR FOR
SELECT id
FROM #t
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #countyid
WHILE ##FETCH_STATUS = 0
BEGIN
if(#countyid > 0)
BEGIN
INSERT INTO Territory_mapping(TerritoryID,Target_GeographyTypeID,Target_GeographyID,CreatedDate)
VALUES(#TerritoryID,#Target_GeographyTypeID,#countyid,GETDATE())
END
FETCH NEXT FROM db_cursor INTO #countyid
END
CLOSE db_cursor
DEALLOCATE db_cursor
-------------------- Zip Code -----------------------
SELECT #Target_GeographyTypeID=GeographyTypeId from GeoGraphyTypes
WHERE GeographyTypeName='Zipcode'
DECLARE db_cursor CURSOR FOR
SELECT id
FROM #tzip
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #zipcodeid
WHILE ##FETCH_STATUS = 0
BEGIN
IF(#zipcodeid > 0)
BEGIN
INSERT INTO Territory_mapping(TerritoryID,Target_GeographyTypeID,Target_GeographyID,CreatedDate)
VALUES(#TerritoryID,#Target_GeographyTypeID,#zipcodeid,GETDATE())
END
FETCH NEXT FROM db_cursor INTO #zipcodeid
END
CLOSE db_cursor
DEALLOCATE db_cursor
RETURN #TerritoryID
END
Have you tried this:
INSERT INTO Territory_mapping
(TerritoryID,Target_GeographyTypeID,Target_GeographyID,CreatedDate)
Select #TerritoryID, #Target_Geography, id, GETDATE()
From #t
Where id > 0
Note this is purely a rework of your code based on what you provided. I have no idea where some of those variables are coming from.
Also, you say that countryid is a comma separated list of values, but that's not how your code is working with it. My sample assumes (are yours does) that #countryid (and by extension, id) is a single value. If this isn't the case, please update your code to show how you are dealing with the comma separated list.