Ifexists() tsql looping issue - sql-server

DECLARE #tag VARCHAR(MAX)
DECLARE #TagID as INT;
DECLARE #ID as INT;
DECLARE tag_cursor CURSOR
FOR
SELECT tagname FROM #temptag
FOR READ ONLY
OPEN tag_cursor
FETCH NEXT FROM tag_cursor INTO #tag
WHILE ##FETCH_STATUS = 0
BEGIN
IF EXISTS (SELECT TOP 1 * FROM Tag WHERE TagName=#tag)
BEGIN
print 1;
END
print 2;
/* INSERT INTO Tag
SELECT #tag FROM #temptag
SELECT #TagID = SCOPE_IDENTITY();
print #TagID*/
FETCH NEXT FROM tag_cursor INTO #tag
END
CLOSE tag_cursor
DEALLOCATE tag_cursor
In my stored procedure I am searching for a value in the table. If the value already exists then I should not insert value.
so I have written
IF EXISTS (SELECT TOP 1 * FROM Tag WHERE TagName=#tag)
BEGIN
print 1;
END
print 2;
/* INSERT INTO Tag
SELECT #tag FROM #temptag
SELECT #TagID = SCOPE_IDENTITY();
print #TagID*/
FETCH NEXT FROM tag_cursor INTO #tag
END
Problem: When I run it both values print1 and print 2 are getting printed
Can someone help me in fixing the error

Perhaps you meant to have an ELSE block?
IF EXISTS (SELECT TOP 1 * FROM Tag WHERE TagName=#tag)
BEGIN
print 1;
END
ELSE
BEGIN
print 2;
/* INSERT INTO Tag
SELECT #tag FROM #temptag
SELECT #TagID = SCOPE_IDENTITY();
print #TagID*/
END

Related

T-SQL 2008- Exit when Value is NULL

I am looking for a way to exit an T-SQL script when #Value is null. This is what I have so far but it does not work as expected:
SELECT
#Value,
CASE
WHEN #Value IS NULL
RAISERROR('EXIT', 16, 1)
FROM
table
WHERE
name LIKE 'test'
Perhaps this will work for you:
DECLARE #Value INT = 1
IF( #Value IS NULL)
BEGIN
RAISERROR('Exit',16,1)
END
ELSE
BEGIN
SELECT #Value
END
IF #Value IS NULL RAISERROR('EXIT', 16,1);
Using a cursor and a temp table you can get the output you want. don't know if that's the goal,
USE AdventureWorksLT2012
DECLARE #CustomerID AS INT
DECLARE #CompanyName AS VARCHAR(MAX)
DECLARE #EmailAddress AS VARCHAR(MAX)
CREATE TABLE #output (CustomerID INT,CompanyName VARCHAR(MAX),EmailAddress VARCHAR(MAX))
DECLARE testCursor CURSOR
FOR
SELECT TOP (100)
CustomerID
,CompanyName
,EmailAddress
FROM SalesLT.Customer
ORDER BY customerID DESC;
OPEN testCursor;
FETCH NEXT FROM testCursor
INTO #CustomerID, #CompanyName, #emailAddress;
if #EmailAddress is not null
BEGIN
INSERT INTO #output values( #CustomerID, #CompanyName, #emailAddress);
WHILE ##FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM testCursor
INTO #CustomerID, #CompanyName, #emailAddress;
if #EmailAddress is null
BEGIN
RAISERROR('Exit',16,1);
BREAK;
end
INSERT INTO #output values( #CustomerID, #CompanyName, #emailAddress);
END;
END
CLOSE testCursor;
DEALLOCATE testCursor;
SELECT * FROM #output;
DROP TABLE #output

Check if record exists, if yes “update” if not “insert” using cursor sql server

I have this trigger that after insert update and insert data in a table, using the if as paramter for the insert or update, at the same time i have another trigger after update that changes another register. The problem is that the first trigger when does the update it trigger the update trigger... So occours that I had to protect the first trigger by checking if there´s a register there before the insert BUT I have a cursor to insert the data in the middle of all this, after I did checking the insert of one register occurs BUT the others inside the cursor aren´t inserted in the table just one register of the list in the cursor... I cannot find the problem, please help...
this is my trigger:
ALTER TRIGGER [dbo].[tr_inclusao_dupla] ON [dbo].[tb_patrimonio]
AFTER INSERT
AS
BEGIN
begin try
IF EXISTS (SELECT * FROM INSERTED) AND EXISTS (SELECT * FROM DELETED)
BEGIN
declare #id as int
declare #count as int
declare #qtd as int
declare #emlote as bit
declare #nr_serie as varchar(100)
declare #nr_patrimonio as varchar(100)
declare #dm_identificado as bit
declare #nr_inventario as varchar(100)
set #nr_patrimonio = (select nr_patrimonio_efetivo from inserted)
set #nr_serie = (select nr_serie from inserted)
set #nr_inventario = (select nr_inventario from inserted)
/*single insert*/
if (#nr_patrimonio is not null or #nr_serie is not null or #nr_inventario is not null)
begin
set #emlote =0
declare registros cursor for
select cd_patrimonio , nr_qtd_lote,nr_serie, nr_patrimonio_efetivo from inserted
open registros
fetch next from registros into #id, #qtd, #nr_serie, #nr_patrimonio
while( ##fetch_status = 0)
begin
set #dm_identificado = 1
update tb_patrimonio set dm_identificado = #dm_identificado, dm_em_lote = #emlote
where cd_patrimonio = #id
end
fetch next from registros into #id, #qtd,#nr_serie, #nr_patrimonio
close registros
deallocate registros
end
END
ELSE
BEGIN
/*multiple insert*/
begin
set #emlote =0
set #dm_identificado = 0
declare registros2 cursor for
select cd_patrimonio , nr_qtd_lote,nr_serie, nr_patrimonio_efetivo from inserted
open registros2
fetch next from registros2 into #id, #qtd, #nr_serie, #nr_patrimonio
while( ##fetch_status = 0)
begin
print #qtd
set #count = 1
update tb_patrimonio set dm_identificado = #dm_identificado, dm_em_lote = #emlote
where cd_patrimonio = #id
while (#count <= (#qtd-1))
begin
INSERT INTO [dbo].[tb_patrimonio]
([dm_patrimonio]
,[dm_em_lote]
,[nr_qtd_lote]
,[cd_grupo_produto]
,[nm_patrimonio]
,[nr_patrimonio_efetivo]
,[nr_patrimonio_antigo]
,[nr_serie]
,[ds_descricao]
,[nr_lacre]
,[cd_barra]
,[dm_tipo_entrada]
,[nr_garantia]
,[cd_nota_fiscal]
,[ds_garantia]
,[img_patrimonio]
,[cd_situacao_patrimonio]
,[cd_orgao]
,[cd_local]
,[dm_situacao]
,[cd_usuario_inc]
,[cd_estado_patrimonio]
,[cd_tipo_posse]
,[cd_usuario_alt]
,[dt_alteracao]
,[cd_usuario]
,[dt_inclusao]
,[cd_estado_equipamento]
,[cd_fornecedor]
,[nr_termo]
,[img_termo]
,[dm_identificado]
,[dt_instalacao_equipamento]
,[nr_inventario])
SELECT
[dm_patrimonio]
,#emlote
,[nr_qtd_lote]
,[cd_grupo_produto]
,[nm_patrimonio]
,[nr_patrimonio_efetivo]
,[nr_patrimonio_antigo]
,[nr_serie]
,[ds_descricao]
,[nr_lacre]
,[cd_barra]
,[dm_tipo_entrada]
,[nr_garantia]
,[cd_nota_fiscal]
,[ds_garantia]
,[img_patrimonio]
,[cd_situacao_patrimonio]
,[cd_orgao]
,[cd_local]
,[dm_situacao]
,[cd_usuario_inc]
,[cd_estado_patrimonio]
,[cd_tipo_posse]
,[cd_usuario_alt]
,[dt_alteracao]
,[cd_usuario]
,[dt_inclusao]
,[cd_estado_equipamento]
,[cd_fornecedor]
,[nr_termo]
,[img_termo]
,#dm_identificado
,[dt_instalacao_equipamento]
,[nr_inventario]
FROM inserted where cd_patrimonio = #id
set #count = #count + 1
end
fetch next from registros2 into #id, #qtd,#nr_serie, #nr_patrimonio
end
close registros2
deallocate registros2
end
END
end try
begin catch
declare #errormessage nvarchar(4000)
declare #errorseverity int
declare #errorstate int
select
#errormessage = ERROR_MESSAGE(),
#errorseverity = ERROR_SEVERITY(),
#errorstate = ERROR_STATE()
raiserror (
#errormessage,
#errorseverity,
#errorstate
)
end catch end

Adding Column to stored procedure conditionally

I have the following (simplified) stored procedure:
CREATE FUNCTION [dbo].[UDF_FulfilmentBatch](#FulfilmentID INT) RETURNS
#Result TABLE (
[sequence] INT,
membershipid BIGINT,
membershipNo VARCHAR(255)
)
AS
BEGIN
DECLARE #_sequence INT
DECLARE #_membershipid BIGINT
DECLARE #_membershipNo VARCHAR(255)
SET #_sequence = 1
IF #FulfilmentID = 4
BEGIN
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_HH
END
IF #FulfilmentID = 3
BEGIN
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_ID
END
ELSE IF #FulfilmentID = 2
BEGIN
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_Art
END
ELSE
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_Tha
OPEN FulfilCursor
FETCH NEXT FROM FulfilCursor INTO #_membershipid, #_membershipNo
WHILE ##FETCH_STATUS = 0 BEGIN
INSERT INTO #Result
VALUES (#_sequence, #_membershipid, #_membershipNo)
SET #_sequence = #_sequence + 1
FETCH NEXT FROM FulfilCursor INTO #_membershipid, #_membershipNo
END
CLOSE FulfilCursor
DEALLOCATE FulfilCursor
RETURN
END
GO
My problem is, that when FulfilmentID = 4, I wan to add an extra field - 'Delivery'
If have tried the following:
CREATE FUNCTION [dbo].[UDF_FulfilmentBatch](#FulfilmentID INT) RETURNS
#Result TABLE (
[sequence] INT,
membershipid BIGINT,
membershipNo VARCHAR(255)
IF #FulfilmentID = 4
BEGIN
,Delivery VARCHAR(255)
END
)
AS
BEGIN
DECLARE #_sequence INT
DECLARE #_membershipid BIGINT
DECLARE #_membershipNo VARCHAR(255)
IF #FulfilmentID = 4
BEGIN
DECLARE #_Delivery VARCHAR(255)
END
SET #_sequence = 1
IF #FulfilmentID = 4
BEGIN
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_HH
END
IF #FulfilmentID = 3
BEGIN
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_ID
END
ELSE IF #FulfilmentID = 2
BEGIN
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_Art
END
ELSE
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_Tha
OPEN FulfilCursor
FETCH NEXT FROM FulfilCursor INTO #_membershipid, #_membershipNo
WHILE ##FETCH_STATUS = 0 BEGIN
INSERT INTO #Result
VALUES (#_sequence, #_membershipid, #_membershipNo IF #FulfilmentID=4 BEGIN #_Delivery )
SET #_sequence = #_sequence + 1
FETCH NEXT FROM FulfilCursor INTO #_membershipid, #_membershipNo
END
CLOSE FulfilCursor
DEALLOCATE FulfilCursor
RETURN
END
GO
But this did not work (Please excuse any syntax errors, this is a rough typing for SO)
Form searching the web there does not seem to be much on this. Can it be done?
There are lots of issues in your code:
use SELECT *
use Cursor
...
In the end, it is overly complicated and looks at lot like Application code (C#, java, ...)
What you want to do should be done with a single Select (ie. on a set of data). Columns names should also be listed between SELECT and FROM.
One option is:
CREATE FUNCTION [dbo].[UDF_FulfilmentBatch](#FulfilmentID INT) RETURNS TABLE
AS
RETURN (
SELECT sequence = ROW_NUMBER() Over(Order By (Select 1))
, _membershipid, membershipNo, delivery
FROM VW_FulfilmentExtract_HH
WHERE #FulfilmentID = 4
UNION ALL
SELECT sequence = ROW_NUMBER() Over(Order By (Select 1))
, _membershipid, membershipNo, delivery = NULL
FROM VW_FulfilmentExtract_ID
WHERE #FulfilmentID = 3
UNION ALL
SELECT sequence = ROW_NUMBER() Over(Order By (Select 1))
, _membershipid, membershipNo, delivery = NULL
FROM VW_FulfilmentExtract_Art
WHERE #FulfilmentID = 2
UNION ALL
SELECT sequence = ROW_NUMBER() Over(Order By (Select 1))
, _membershipid, membershipNo, delivery = NULL
FROM VW_FulfilmentExtract_Tha
WHERE #FulfilmentID = not in (2, 3, 4)
);
Here I use ROW_NUMBER to generate your sequence number.
I added the Delivery column and set it to NULL when it is not needed.
You must update columns name. I just guess them.
By the way, this is not a Stored Procedure but a Inline User-Defined Functions

##FETCH_STATUS lives outside the cursor

I have a query which processes XML data and I use a while(##FETCH_STATUS = 0) loop for data returned from the cursor.
When I run the query using Management Studio, ##FETCH_STATUS equals -1 and the code inside my loop is omitted. If I run the query using the debugger and press continue, it runs just fine and the ##FETCH_STATUS equals 0. When I run the query again, after running it in debug ##FETCH_STATUS equals 0 and changes to -1.
To sum up:
I run with SSMS - ##FETCH_STATUS = -1
I run with debugger - ##FETCH_STATUS = 0 (I want this value)
I run with SSMS once after running with debugger ##FETCH_STATUS still equals 0 but then changes to -1.
I use OPEN cursor, CLOSE cursor and DEALLOCATE cursor. Why does it work this way?
EDIT: Code you asked for:
IF (OBJECT_ID('dbo.XmlOrderResponses') IS NOT NULL)
DROP TABLE XmlOrderResponses;
CREATE TABLE XmlOrderResponses (
OrderResponseType INT
,OrderResponseNumber NVARCHAR(40)
,OrderResponseDate DATETIME
,DocumentFunctionCode NVARCHAR(40)
,Remarks INT
);
DECLARE CUR CURSOR
FOR
SELECT Subdirectory
FROM XMLFiles;
OPEN CUR
WHILE (##FETCH_STATUS = 0)
BEGIN
DECLARE #DocHandle AS INT;
DECLARE #TMP AS NVARCHAR(512);
FETCH NEXT
FROM Cur
INTO #TMP
DECLARE #XmlDocument AS NVARCHAR(MAX);
SET #XmlDocument = (
SELECT CAST(XMLSource AS NVARCHAR(max))
FROM XMLFiles
WHERE subdirectory = #TMP
);
EXEC sys.sp_xml_preparedocument #DocHandle OUTPUT
,#XmlDocument;
INSERT INTO XmlOrderResponses (
OrderResponseType
,OrderResponseNumber
,OrderResponseDate
,DocumentFunctionCode
,Remarks
)
SELECT *
FROM OPENXML(#DocHandle, '/Document-OrderResponse/*', 11) WITH (
OrderResponseType INT
,OrderResponseNumber NVARCHAR(40)
,OrderResponseDate DATETIME
,DocumentFunctionCode NVARCHAR(40)
,Remarks INT
);
EXEC sys.sp_xml_removedocument #DocHandle;
END
CLOSE CUR;
DEALLOCATE CUR;
--I know I shouldn't be doing that but I can't get rid of NULL records the other way.
DELETE
FROM XmlOrderResponses
WHERE OrderResponseType IS NULL
AND OrderResponseNumber IS NULL
AND OrderResponseDate IS NULL
AND DocumentFunctionCode IS NULL
AND Remarks IS NULL;
SELECT *
FROM XmlOrderResponses
SELECT ##FETCH_STATUS
The problem is that the first time you refer to ##FETCH_STATUS, you have not done a fetch with your cursor, so it is referring to the last cursor used. Imagine this simple example:
DECLARE C1 CURSOR
FOR
SELECT TOP 3 ID
FROM (VALUES ('1'), ('2'), ('3')) t (ID);
OPEN C1;
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #c1 CHAR(1);
FETCH NEXT FROM C1 INTO #c1;
PRINT #c1;
END
CLOSE C1;
DEALLOCATE C1;
DECLARE C2 CURSOR
FOR
SELECT TOP 3 ID
FROM (VALUES ('1'), ('2'), ('3')) t (ID);
OPEN C2;
-- HERE ##FETCH_STATUS REFERS TO THE LAST FETCH FOR CURSOR `C1` NOT `C2`
SELECT ##FETCH_STATUS;
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #c2 CHAR(1);
FETCH NEXT FROM C2 INTO #c2;
PRINT #c2;
END;
CLOSE C2;
DEALLOCATE C2;
At the commented line, even though you have closed, and deallocated C1, ##FETCH_STATUS is still referring to this cursor (since no other FETCH has been performed since), so you never enter your loop for C2
You should perform the Fetch before the loop, then at the end of each loop, rather than at the beginning.
DECLARE #TMP AS NVARCHAR(512);
OPEN CUR
-- DO FETCH FIRST
FETCH NEXT FROM Cur INTO #TMP
WHILE (##FETCH_STATUS = 0)
BEGIN
DECLARE #DocHandle AS INT;
-- DO ALL YOUR WORK WITH #TMP
--PERFORM THE FETCH AGAIN AT THE END OF THE LOOP
FETCH NEXT FROM Cur INTO #TMP
END
The other problem you have with doing FETCH at the start of each loop, is that the last item will be processed twice. Again a simple example (and assuming you enter the loop with ##FETCH_STATUS = 0)
DECLARE C1 CURSOR
FOR
SELECT ID = '1';
OPEN C1;
DECLARE #c CHAR(1);
WHILE (##FETCH_STATUS = 0)
BEGIN
DECLARE #c1 CHAR(1);
FETCH NEXT FROM C1 INTO #c1;
PRINT #c1;
END
This will print
1
1
Because, when ##FETCH_STATUS is -1, FETCH will just return the item at the current position.

How i can use cursor to delete record from table

I want to use cursor to delete record from table. How can I do it?
I use MSSQL 2008 Express this code does not delete anything from #temp. I also tried where current of cursor_name did not work.
Here is my sample code:
use AdventureWorks
drop table #temp
select * into #temp from HumanResources.Employee;
declare #eid as int;
declare #nid as varchar(15);
DECLARE Employee_Cursor CURSOR FOR
SELECT A.EmployeeID, A.NationalIDNumber FROM #temp AS A
OPEN Employee_Cursor;
FETCH NEXT FROM Employee_Cursor INTO #eid , #nid ;
WHILE ##FETCH_STATUS = 0
BEGIN
IF (#eid > 10)
BEGIN
delete from #temp where #temp.EmployeeID = #eid;
END
FETCH NEXT FROM Employee_Cursor;
END;
CLOSE Employee_Cursor;
DEALLOCATE Employee_Cursor;
GO
select * from #temp
thanks in advance
use AdventureWorks
select * into #temp from HumanResources.Employee;
declare #eid as int;
declare #nid as varchar(15);
DECLARE Employee_Cursor CURSOR FOR
SELECT A.EmployeeID, A.NationalIDNumber FROM #temp AS A
OPEN Employee_Cursor;
FETCH NEXT FROM Employee_Cursor INTO #eid , #nid ;
WHILE ##FETCH_STATUS = 0
BEGIN
IF (#eid > 10)
BEGIN
delete from #temp where current of Employee_Cursor
END
FETCH NEXT FROM Employee_Cursor INTO #eid , #nid ;
END;
CLOSE Employee_Cursor;
DEALLOCATE Employee_Cursor;
select * from #temp
drop table #temp
this works for me
There is a much simpler answer - use this command:
delete from HumanResources.Employee where current of Employee_Cursor
It's called 'Positioned delete' and described at MSDN.
Could you please try in below ways, thanks for your time.
You have fetched data from cursor but didn't push into your variables missed in WHILE loop, please have a look on below code, thanks.
drop table #temp
select * into #temp from Employee;
declare #eid as int;
declare #nid as varchar(15);
DECLARE Employee_Cursor CURSOR FOR
SELECT A.EmployeeID, A.NationalIDNumber FROM #temp AS A
OPEN Employee_Cursor;
FETCH NEXT FROM Employee_Cursor INTO #eid , #nid ;
WHILE ##FETCH_STATUS = 0
BEGIN
IF (#eid > 10)
BEGIN
delete from #temp where #temp.EmployeeID = #eid;
END
FETCH NEXT FROM Employee_Cursor INTO #eid , #nid ;
END;
CLOSE Employee_Cursor;
DEALLOCATE Employee_Cursor;
GO
select * from #temp
Update:
I've changes in 2nd FETCH statement, just have added below highlighted part, thanks
FETCH NEXT FROM Employee_Cursor INTO #eid , #nid ;

Resources