How to compare each string from first column with each string in second column in TSQL? - sql

Here is the code I tried:
declare #o1 nvarchar(255)
declare #o2 nvarchar(255)
declare data cursor for
select o1.Name, o2.Name from MyDB.dbo.Table1 as o1, MyDB.dbo.MyTable2 as o2;
OPEN data;
-- Perform the first fetch.
FETCH NEXT FROM data into #o1, #o2;
-- Check ##FETCH_STATUS to see if there are any more rows to fetch.
WHILE ##FETCH_STATUS = 0
BEGIN
-- This is executed as long as the previous fetch succeeds.
FETCH NEXT FROM data INTO #o1, #o2;
Print 'Name1: ' + #o1
WHILE ##FETCH_STATUS = 0
BEGIN
-- This is executed as long as the previous fetch succeeds.
FETCH NEXT FROM data INTO #o1, #o2;
Print 'Name2: ' + #o2
END
END
CLOSE data;
DEALLOCATE data;
GO
I am getting two columns in my query and both are nvarchar(255).
I want to compare each value from the first column with each value of the second column. That can be achieved with loop inside a loop, but I don't know what should I do with the cursor part.
Should I put a variable and keep fetch status separately?
Or somethings else will do the trick?

I think that you don't need a cursor you can use select :
Select o1, O2
from table1
where o1 in (select o2 from table1)

Related

Why is my T-SQL cursor executing twice?

SQL-Server Code:
Declare #offers VARCHAR(100)
Declare #offers_seq VARCHAR(100)
Declare Result Cursor
For Select Top 1 Offers,Offers_seq From [REZJQWB01]..ActiveBooking_OffersDetails_Seq
Open Result
While ##fetch_status=0
Begin
Fetch Next From Result Into #offers, #offers_seq
Declare #value VARCHAR(100) = #offers
While len(#value) >= 1
Begin
Set #value = substring(#value,charindex(';',#value)+1,len(#value))
Print #value
End
End
Close Result
Deallocate Result
What I'm trying to accomplish here is to split a set of delimited values present in one cell and then creating a cursor for the complete column. The first time I run this code it gives the below output:
2;6;7;8;9;12;13;14;17;19;21;
6;7;8;9;12;13;14;17;19;21;
7;8;9;12;13;14;17;19;21;
8;9;12;13;14;17;19;21;
9;12;13;14;17;19;21;
12;13;14;17;19;21;
13;14;17;19;21;
14;17;19;21;
17;19;21;
19;21;
21;
2;6;7;8;9;12;13;14;17;19;21;
6;7;8;9;12;13;14;17;19;21;
7;8;9;12;13;14;17;19;21;
8;9;12;13;14;17;19;21;
9;12;13;14;17;19;21;
12;13;14;17;19;21;
13;14;17;19;21;
14;17;19;21;
17;19;21;
19;21;
21;
Ideally It should Print only once but I'm not sure why the loop runs twice. The second time I run this, it gives the output as : 'Command(s) completed successfully'.
Kindly help.
Thanks.
The reason it is running twice is that you aren't doing the fetch until after you've already checked the ##fetch_status.
The steps look like this:
Check ##fetch_status, which is zero, since nothing has been fetched.
Fetch a result
Run your substring code
Check ##fetch_status again, which is still zero, because a record was fetched in the previous step
Fetch another result, which fails but the cursor is still pointing at the same row as before
Run your substring code again, same result
Check ##fetch_status again, which now returns -1 because the previous fetch failed.
For the same reason as you get two results from running it once, you get nothing the second time, because ##fetch_status is -1 from the previous execution. To fix both issues, you need to fetch before checking the status. Usually you'll see one of the following methods employed (psuedocode left as an exercise for you to implement). Typically I use the first option, but some find the second is easier to read:
-- (declare and open cursor)
while 1=1 begin
fetch next from cursor
if ##fetch_status <> 0 break;
-- (do stuff)
end
or
-- (declare and open cursor)
fetch next from cursor
while ##fetch_status = 0 begin
-- (do stuff)
fetch next from cursor
end
Correct Code:
Declare #offers VARCHAR(100)
Declare #offers_seq VARCHAR(100)
Declare Result Cursor
For Select Top 1 Offers,Offers_seq From [REZJQWB01]..ActiveBooking_OffersDetails_Seq
Open Result
While 1=1
Begin
Fetch Next From Result Into #offers, #offers_seq
If ##fetch_status <> 0 Break;
Declare #value VARCHAR(100) = #offers
While len(#value) > 1
Begin
Set #value = substring(#value,charindex(';',#value,2)+1,len(#value))
Set #value = ';'+#value
If len(#value) <= 1 Break;
Print #value
End
End
Close Result
Deallocate Result
Result:
;6;7;8;9;12;13;14;17;19;21;
;7;8;9;12;13;14;17;19;21;
;8;9;12;13;14;17;19;21;
;9;12;13;14;17;19;21;
;12;13;14;17;19;21;
;13;14;17;19;21;
;14;17;19;21;
;17;19;21;
;19;21;
;21;

process each row in table in stored procedure using cursor

My Scenario is bit different. what i am doing in my stored procedure is
Create Temp Table and insert rows it in using "Cursor"
Create Table #_tempRawFeed
(
Code Int Identity,
RawFeed VarChar(Max)
)
Insert Data in temp table using cursor
Set #GetATM = Cursor Local Forward_Only Static For
Select DeviceCode,ReceivedOn
From RawStatusFeed
Where C1BL=1 AND Processed=0
Order By ReceivedOn Desc
Open #GetATM
Fetch Next
From #GetATM Into #ATM_ID,#Received_On
While ##FETCH_STATUS = 0
Begin
Set #Raw_Feed=#ATM_ID+' '+Convert(VarChar,#Received_On,121)+' '+'002333'+' '+#ATM_ID+' : Bills - Cassette Type 1 - LOW '
Insert Into #_tempRawFeed(RawFeed) Values(#Raw_Feed)
Fetch Next
From #GetATM Into #ATM_ID,#Received_On
End
Now have to process each row in Temp Table using another Cursor
DECLARE #RawFeed VarChar(Max)
DECLARE Push_Data CURSOR FORWARD_ONLY LOCAL STATIC
FOR SELECT RawFeed
FROM #_tempRawFeed
OPEN Push_Data
FETCH NEXT FROM Push_Data INTO #RawFeed
WHILE ##FETCH_STATUS = 0
BEGIN
/*
What Should i write here to retrieve each row one at a time ??
One Row should get stored in Variable..in next iteration previous value should get deleted.
*/
FETCH NEXT FROM Push_Data INTO #RawFeed
END
CLOSE Push_Data
DEALLOCATE Push_Data
Drop Table #_tempRawFeed
What Should i write In BEGIN to retrieve each row one at a time ??
One Row should get stored in Variable..in next iteration previous value should get deleted.
Regarding your last question, if what you are really intending to do within your last cursor is to concatenate RawFeed column values into one variable, you don't need cursors at all. You can use the following (adapted from your SQL Fiddle code):
CREATE TABLE #_tempRawFeed
(
Code Int IDENTITY
RawFeed VarChar(MAX)
)
INSERT INTO #_tempRawFeed(RawFeed) VALUES('SAGAR')
INSERT INTO #_tempRawFeed(RawFeed) VALUES('Nikhil')
INSERT INTO #_tempRawFeed(RawFeed) VALUES('Deepali')
DECLARE #RawFeed VarChar(MAX)
SELECT #RawFeed = COALESCE(#RawFeed + ', ', '') + ISNULL(RawFeed, '')
FROM #_tempRawFeed
SELECT #RawFeed
DROP TABLE #_tempRawFeed
More on concatenating different row values into a single string here: Concatenate many rows into a single text string?
I am pretty sure that you can avoid using the first cursor as well. Please, avoid using cursors, since the really hurt performance. The same result can be achieved using set based operations.

How to replace cursor code with CTE in sql server 2008

I have a condition where I need to pull id's from one master table and then based on that value pull values from two different tables and then update/insert into third table with these values.
I am using cursor to loop through the records in master table however I feel like this is leading to performance issue. I wanted to know if this can be done using CTE or not. I tried using CTE but it is non recursive and I am totally lost where I am going wrong.
Here is how my stored procedure is -
//
BEGIN
declare #variables char(10);
DECLARE #cursor CURSOR; --DECLARE CURSOR
SET #cursor = CURSOR FOR -- SET CURSOR
-- pull in value for curso
OPEN #cursor
FETCH NEXT
FROM #cursor INTO #variables --FILL IN CURSOR TO LOOP THROUGH
WHILE ##FETCH_STATUS = 0
BEGIN
BEGIN
--PUll values from table 1
END
BEGIN
--Pull values from table 1
-- Do some maths on the values pulled
END
BEGIN
--function/sql to update or insert
END
FETCH NEXT
FROM #cursor INTO #variables;
END
CLOSE #cursor;
DEALLOCATE #cursor;
END
//
With CTE, my code is -
//
;WITH CTE AS
(
--pull values from master table
)
BEGIN
BEGIN
-- pull values from table 1
END
BEGIN
-- Pull values from table 2, do the calculations
END
BEGIN
-- insert or update as needed.
END
//

FOR UPDATE cursor is returning a result set for each row!

I'm using an UPDATE cursor as follows on SQL 2005:
DECLARE myCursor CURSOR FOR
SELECT RowID, Value FROM myTable
FOR UPDATE OF Value;
OPEN myCursor;
FETCH NEXT FROM myCursor
WHILE (##FETCH_STATUS <> -1)
UPDATE myTable SET Value = 42
WHERE CURRENT OF myCursor
FETCH NEXT FROM myCursor
END
CLOSE myCursor
DEALLOCATE myCursor
(Thanks to Matt for his correct answer on my prior question concerning this cursor syntax. And yes, I do need a cursor, because each row's new value is actually based on a complicated calculation that depends on the prior rows.)
This works correctly, updating all the Values. The problem is that it returns a result set for each row updated, consisting of RowID, Value (interestingly, its showing the result from before the row is updated). Eventually, I get the following error:
The query has exceeded the maximum
number of result sets that can be
displayed in the results grid. Only
the first 100 result sets are
displayed in the grid.
Any way to suppress these result sets? SET NOCOUNT ON doesn't do the trick.
Is this just an issue I see running it directly in SSMS? Or will it actually try to return hundreds of result sets when I put this cursor inside a stored proc?
EDIT: Looks like it has nothing to do with the UPDATE.
Using FETCH NEXT FROM myCURSOR the way I am actually does return a result set of the next row from the cursor.
If I change it to FETCH NEXT FROM myCURSOR INTO #variables, then it doesn't return a result set.
So I guess the question now is: Since I'm using WHERE CURRENT OF, I don't really need the variable. I guess I can put them in just to suppress the result set, but is there a better way to do it?
Note while begin ... end
and Fetch into
Declare #row int
Declare #value int
DECLARE myCursor CURSOR FOR
SELECT RowID, Value FROM myTable
FOR UPDATE OF Value;
OPEN myCursor;
FETCH NEXT FROM myCursor into #row, #value
WHILE (##FETCH_STATUS <> 1)
begin
UPDATE myTable SET Value = 42
WHERE CURRENT OF myCursor
FETCH NEXT FROM myCursor into #row, #value
END
CLOSE myCursor
DEALLOCATE myCursor

Select returns 0 rows in a cursor and right number of rows in manual running

I've this cursor declaration:
DECLARE CursorArticulo CURSOR FOR
SELECT HstAt.IdArticulo, SUM(HstAt.Cantidad) As SumaCantidad,
HstAt.Precio
FROM HstArticulosTickets hstAT INNER JOIN HstTickets HstT
ON hstAT.IdTicket=hstT.IdTicket
WHERE hstT.NumUsuarioEmisor=#UsuarioAct
AND HstT.NumZona=#ZonaAct
AND DATEDIFF(day,#par_Fecha,HstT.FechaHoraTicket)=0
GROUP BY IdArticulo, Precio
ORDER BY IdArticulo
The parameters #UsuarioAct and #ZonaAct are obtained from another Cursor. The #par_Fecha parameter is an input parameter for a Stored procedure.
If I run the stored procedure, in this cursor I never get a single row. Never enters into the typical WHILE ##FETCH_STATUS = 0 loop.
I try in query analyzer copying the select code and replacing parameters with values and I get the correct rows.
I'm running this in SQL Server 2008.
Why does this happen?
Thank you all.
EDIT:
Full Stored Procedure Code:
ALTER PROCEDURE [dbo].[paCreTablaHojaDeCajaMA]
#par_Fecha AS DATETIME
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DELETE FROM dbo.TmpDetalleHojaDeCajaDiaria
DELETE FROM dbo.TmpMaestraHojaDeCajaDiaria
INSERT INTO TmpMaestraHojaDeCajaDiaria
(NumUsuario, ZonaAsignada, TipoUsuario, NumPDA, ImporteUsuarioZona)
SELECT
hstZA.NumUsuario, hstZA.NumZonaAsignada,
(SELECT TipoUsuario FROM Usuarios U WHERE U.NumUsuario=hstZA.NumUsuario) AS TipoUsuario,
(SELECT NumPDA FROM Usuarios U WHERE U.NumUsuario=hstZA.NumUsuario) AS NumPDA,
(SELECT SUM(hstT.ImporteTotal) FROM HstTickets hstT
WHERE hstT.NumUsuarioEmisor=hstZA.NumUsuario
AND hstT.NumZona=hstZA.NumZonaAsignada
AND DATEDIFF(day,hstZA.Fecha,HstT.FechaHoraTicket)=0) AS ImporteUsuarioZona
FROM hstZonasAsignadas hstZA
WHERE DATEDIFF(day,hstZA.Fecha,#par_Fecha)=0
ORDER BY NumUsuario
DECLARE #UsuarioAct NCHAR(4)
DECLARE #ZonaAct SMALLINT
DECLARE #IdUnicoAct INTEGER
DECLARE #IdArticulo INTEGER
DECLARE #NombreArticulo NCHAR(50)
DECLARE #PrecioUd MONEY
DECLARE #SumaCantidad INTEGER
DECLARE CursorMaestra CURSOR FOR
SELECT NumUsuario, ZonaAsignada, IdUnico FROM TmpMaestraHojaDeCajaDiaria
ORDER BY NumUsuario
OPEN CursorMaestra
PRINT 'CURSOR ABIERTO'
-- Vamos a por el primero
FETCH NEXT FROM CursorMaestra INTO #ZonaAct, #UsuarioAct, #IdUnicoAct
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #ZonaAct
PRINT #UsuarioAct
DECLARE CursorArticulo CURSOR FOR
(SELECT HstAt.IdArticulo, SUM(HstAt.Cantidad) As SumaCantidad, HstAt.Precio
FROM HstArticulosTickets hstAT INNER JOIN HstTickets HstT
ON hstAT.IdTicket=hstT.IdTicket
WHERE hstT.NumUsuarioEmisor=#UsuarioAct
AND HstT.NumZona=#ZonaAct
AND DATEDIFF(day,#par_Fecha,HstT.FechaHoraTicket)=0
GROUP BY IdArticulo, Precio)
OPEN CursorArticulo
PRINT ' CURSOR ABIERTO'
-- Vamos a por el primero
FETCH NEXT FROM CursorArticulo INTO #IdArticulo, #SumaCantidad, #PrecioUd
PRINT ##FETCH_STATUS
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #NombreArticulo = NombreArticulo FROM Articulos
WHERE IdArticulo = #IdArticulo
PRINT #NombreArticulo
INSERT INTO TmpDetalleHojaDeCajaDiaria
(NumUsuario, ZonaAsignada, IdArticulo, NombreArticulo, PrecioUD, CantidadZonaUsuario, IdUnicoMaestra)
VALUES
(#UsuarioAct, #ZonaAct, #IdArticulo, #NombreArticulo, #PrecioUd, #SumaCantidad, #IdUnicoAct)
FETCH NEXT FROM CursorArticulo INTO #IdArticulo, #SumaCantidad, #PrecioUd
END
CLOSE CursorArticulo
DEALLOCATE CursorArticulo
PRINT ' CURSOR CERRADO'
FETCH NEXT FROM CursorMaestra INTO #ZonaAct, #UsuarioAct, #IdUnicoAct
END
CLOSE CursorMaestra
DEALLOCATE CursorMaestra
PRINT 'CURSOR CERRADO'
END
Can you try adding parenthesis for select like
DECLARE CursorArticulo CURSOR FOR
(
SELECT HstAt.IdArticulo, SUM(HstAt.Cantidad) As SumaCantidad, HstAt.Precio
FROM HstArticulosTickets hstAT INNER JOIN HstTickets HstT
ON hstAT.IdTicket=hstT.IdTicket
WHERE hstT.NumUsuarioEmisor=#UsuarioAct
AND HstT.NumZona=#ZonaAct
AND DATEDIFF(day,#par_Fecha,HstT.FechaHoraTicket)=0
GROUP BY IdArticulo, Precio
ORDER BY IdArticulo
)
are the variables #UsuarioAct and #ZonaAct getting populated ? Can you try replacing the same with the one when you tried in manual query?
Have the variables #UsuarioAct and #ZonaAct been declared as the correct data types?
Maybe an implicit conversion is subtly changing the meaning of the data?
I've found it!
If you read the Outer cursor declaration:
DECLARE CursorMaestra CURSOR FOR
SELECT NumUsuario, ZonaAsignada, IdUnico FROM TmpMaestraHojaDeCajaDiaria
ORDER BY NumUsuario
The order is NumUsuario, ZonaAsignada, IdUnico
But later, in the first FETCH:
FETCH NEXT FROM CursorMaestra INTO #ZonaAct, #UsuarioAct, #IdUnicoAct
I have changed the order, the correct is #UsuarioAct, #ZonaAct, #IdUnicoAct.
So, the User (UsuarioAct) and Zone (ZonaAct) data was wrong.
Thank you all by your tips.
Since you get ##FETCH_STATUS = -1 initially on the inner cursor, I would conclude that your SELECT statement returns no rows. You do mention that you get results when executing the query, but please try the following: the content of the first BEGIN ... END block replace with following code only and see if you do get result sets:
SELECT HstAt.IdArticulo, SUM(HstAt.Cantidad) As SumaCantidad, HstAt.Precio
FROM HstArticulosTickets hstAT
INNER JOIN HstTickets HstT
ON hstAT.IdTicket=hstT.IdTicket
WHERE hstT.NumUsuarioEmisor=#UsuarioAct
AND HstT.NumZona=#ZonaAct
AND DATEDIFF(day,#par_Fecha,HstT.FechaHoraTicket)=0
GROUP BY IdArticulo, Precio
and check if you get any results. If you do not, then remove some of the filters in WHERE clause...