T-SQL: Set Operations Equivalent for cursor operation - sql-server

I have a table like below where I iterate using a cursor to replace one value for another.
Is there a way to do this using set operations in SQL?
In this example, I would replace the column with value 2525 with the value 255 and iterate through using a cursor.
company_name_id replacement_company_name_id
2525 255
11000201010737 10000701010293
12000301010533 12000301010532
Here's the code I am running:
declare #company_name_id bigint, #replacement_company_name_id bigint
declare company_name_cursor cursor for
select
company_name_id
, replacement_company_name_id
from #replacements
open company_name_cursor
fetch next from company_name_cursor into #company_name_id, #replacement_company_name_id
while ##FETCH_STATUS <> -1
begin
update user_job_during_school_job
set company_name_id = #replacement_company_name_id
where company_name_id = #company_name_id
fetch next from company_name_cursor into #company_name_id, #replacement_company_name_id
end
close company_name_cursor
deallocate company_name_cursor

Try this one -
UPDATE uj
SET company_name_id = r.replacement_company_name_id
FROM dbo.user_job_during_school_job uj
JOIN #replacements r ON uj.company_name_id = r.company_name_id

I think you need to show your code for cursor so we have idea of what you are doing. If it's just to replace one column with another, an UPDATE statement could do that
UPDATE myTable SET
company_name_id = replacement_company_name_id
And if restricting the value 2525, then add a WHERE clause
UPDATE myTable SET
company_name_id = replacement_company_name_id
WHERE
company_name_id = 2525

Related

Issues with creating label for our M1 erp software

I am trying to convert an SQL that was written for a previous version of our software. It is grabbing information from an input form, placing them in a temporary table and calculating number of labels and printing a crystal report label accordingly
I have tried changing syntax and removing a where clause ( it is commented out in my code below) that i was unable to link to anything in our new version.
SET NOCOUNT ON
DECLARE #nloop int, #nLabels int
DECLARE #rmlReceiptID varchar(10), #rmlReceiptLineID int, #urmlNOofLabels int
DECLARE LabelsCursor CURSOR READ_ONLY FOR SELECT #rmlReceiptID, #rmlReceiptLineID, #urmlNOofLabels FROM ReceiptLines /* WHERE {?WHERECLAUSE}*/ ORDER BY rmlReceiptID, rmlReceiptLineID
CREATE TABLE #UReceiptLabel (rmlReceiptID varchar(10), rmlReceiptLineID int, CurrentLabel int, TotalLabels int)
SELECT #rmlReceiptID,#rmlReceiptLineID,CONVERT(int,0) As CurrentLabel,CONVERT(int,0) As TotalLabels insert into #UReceiptLabel from ReceiptLines WHERE 0=1
OPEN LabelsCursor
FETCH NEXT FROM LabelsCursor INTO #rmlReceiptID, #rmlReceiptLineID, #urmlNOofLabels
WHILE ##FETCH_STATUS = 0
BEGIN
SET #nloop = 0
SET #nLabels = #urmlNOofLabels
IF #nLabels < 1
SET #nLabels = 1
WHILE (#nloop < #nLabels)
BEGIN
SET #nloop = #nloop + 1
INSERT INTO #UReceiptLabel (rmlReceiptID, rmlReceiptLineID, CurrentLabel, TotalLabels) VALUES (#rmlReceiptID, #rmlReceiptLineID, #nloop, #nLabels)
END
FETCH NEXT FROM LabelsCursor INTO #rmlReceiptID, #rmlReceiptLineID, #urmlNOofLabels
END
CLOSE LabelsCursor
DEALLOCATE LabelsCursor
SET NOCOUNT OFF
SELECT CurrentLabel, TotalLabels, ReceiptLines.rmlReceiptID, ReceiptLines.rmlReceiptLineID, rmlJobID, rmlPartID, rmlJobQuantityReceived, urmlNoOfLabels, urmlQtyInABox, urmlLocation,rmpSupplierOrganizationID, cmoName, rmlDescription, rmlJobAssemblyID
FROM #UReceiptLabel
INNER JOIN ReceiptLines ON ReceiptLines.rmlReceiptID = #UReceiptLabel.rmlReceiptID and ReceiptLines.rmlReceiptLineID = #UReceiptLabel.rmlReceiptLineID
LEFT OUTER JOIN Receipts ON rmpReceiptID = #UReceiptLabel.rmlReceiptID
LEFT OUTER JOIN Organizations On rmpSupplierOrganizationID=cmoOrganizationID ORDER BY #UReceiptLabel.rmlReceiptID,#UReceiptLabel.rmlReceiptLineID,CurrentLabel
DROP TABLE #UReceiptLabel
when i attempt to run the crystal report i get An object or column name is missing or empty. For SELECT INTO statements, verify each column has a name.
I would expect the crystal report to parse the input data and fill the label with appropriate information and print the correct number of labels.

SQL Server trigger Insert/Update specific column

Point is to make a trigger which will:
Check the configuration table which contains a column ConnectionField nvarchar(50)
It should return the string value (columnName) which will be used as a key
So on insert/update on table Workers, the code should set my Xfield value to the value from column ConnectionField, read from the Configuration table.
In short since this is all messy. I want to be able to let my end user to write down in configuration which column he will use as unique (Worker ID, SNSID, Name etc... ) based on his pick trigger need to put that field value to my Xfield
Don't ask why. It's really confusing.
I've written a trigger which will do that but it just is stuck somewhere in an infinite loop
CREATE TRIGGER [dbo].Tr_ConnectionField
ON [dbo].Workers
FOR INSERT, UPDATE
AS
SET NOCOUNT ON;
DECLARE #ID BIGINT
DECLARE #tmpUpit CURSOR;
DECLARE #ConFieldSETUP NVARCHAR(50)
-- Here I will read the field from configuration which will be used as key
SET #ConFieldSETUP = (SELECT TOP 1 ISNULL(ConnectionField, 'SNSID')
FROM ConfigurationTable)
BEGIN
SET #tmpUpit = CURSOR LOCAL SCROLL FOR
SELECT i.id FROM inserted i
OPEN #tmpUpit
END
FETCH NEXT FROM #tmpUpit INTO #ID
WHILE ##fetch_status = 0
BEGIN
-- Here I will use the configuration columns value to my Xfield
UPDATE Workers
SET Xfield = (SELECT #ConFieldSETUP
FROM Workers cld
WHERE cld.Id = #ID)
WHERE Id = #ID
END
FETCH NEXT FROM #tmpUpit INTO #ID
DEALLOCATE #tmpUpit
Try
CREATE TRIGGER [dbo].Tr_ConnectionField ON [dbo].Textt
FOR INSERT, UPDATE AS
SET NOCOUNT ON;
DECLARE #ConFieldSETUP nvarchar(50);
-- Stop recursion for the trigger
IF TRIGGER_NESTLEVEL(OBJECT_ID('dbo.Tr_ConnectionField')) > 1
RETURN;
-- Here i will read the field from configuration which will be used as key
SET #ConFieldSETUP = (SELECT TOP 1 ISNULL(ConnectionField, 'SNSID')
FROM ConfigurationTable
-- ORDER BY ...
);
-- Update Xfield depending on configuration
UPDATE w
SET Xfield = CASE #ConFieldSETUP
WHEN 'SNSID' THEN w.SNSID
WHEN 'Name' THEN w.Name
...
END
FROM Workers w
JOIN inserted i ON i.Id = w.Id;

Commit an temporary table while fetching rows T-SQL (SqlServer2005)

I Update a temporary table during a "While.. fetch next"
The problem is that, when the cursor fetch the next row th e temporary table is not update with the fetch next before so at the end of the while the temporary table it's update with the data of last row instead of data of each row.
Ps : i don't speak very well english, i hope you can understand my request
DECLARE #IdType UNIQUEIDENTIFIER
DECLARE #SerialNumber NVARCHAR(64)
DECLARE DeviceCursor CURSOR LOCAL FOR
SELECT DISTINCT
--Acc.[AccountHierarchyId],
MC.SerialNumber AS SerialNumber,
MC.IdType AS IdType
FROM
#MachinesContrat MC
WHERE
MC.TypeAffaire = 'Essentiel'
OPEN DeviceCursor
FETCH NEXT FROM DeviceCursor INTO #SerialNumber, #IdType
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE
MI SET MI.SerialNumber = #SerialNumber
FROM
#MachinesInventory MI
WHERE
MI.fk_IdType = #IdType AND isnull(MI.SerialNumber,'Dummy') <> #SerialNumber
FETCH NEXT FROM DeviceCursor INTO #SerialNumber, #IdType
END
CLOSE DeviceCursor;
DEALLOCATE DeviceCursor;
You don't need a cursor to do the job. A simple join in your update statement can do it and will be more performant.

Trigger not working when inserting multiple records

I have the following trigger working correctly when I insert one record on table Pedidos.
However, when I insert multiple records I get a 512 error message. I've searched around for details about inserting multiple records and triggers, but not found an answer to my problem.
The trigger reads the inserted records and finds values from other tables to modify the value of the column situacion in table planificaciones.
Am I totally wrong in the way I'm trying to do this? Is there any obvious problems in my trigger?
CREATE TRIGGER TRG_INS_PL_SYNC_STATUS_PLA ON dbo.pedidos after insert as begin if ##ROWCOUNT = 0
return
set nocount on
declare #v_idpla int,
#v_situacion nvarchar(12),
#v_nombre nvarchar(50),
#v_almacen nvarchar(50),
#v_status_pedido nvarchar(4);
set #v_almacen = (select almacen_pedido from inserted);
set #v_nombre =(select cliente from inserted);
set #v_status_pedido = (select status_pedido from inserted);
set #v_situacion = (select top 1 nombre from dbo.StatusPlanificacion
where STATUS_PEDIDO = #v_status_pedido);
set #v_idpla = (select top 1 id from dbo.Planificaciones
where dia_entrega >= GETDATE() and situacion <> 'Departed'
and nombre like '%'+#v_almacen +'%'+ #v_nombre);
if(#v_idpla is not null)
begin
--select Timespan=SYSDATETIME() from inserted;
select ##rowcount;
UPDATE DBO.Planificaciones
SET situacion = #v_situacion
WHERE id = #v_idpla;
end
end
UPDATE & SOLVED: Looking on tanner suggestion i do the next update on code and works, but i think some one can find this more clear and useful. In suggested by tanner, says cursor not best way to do this and the best option is a Join. In my case this insert never goes more than 50 inserts at same time.
CREATE TRIGGER TRG_INS_PL_SYNC_STATUS_PLA
ON dbo.pedidos
after insert as
begin
declare #v_idpla int,#v_situacion nvarchar(12),#v_nombre nvarchar(50),#v_almacen nvarchar(50), #v_status_pedido nvarchar(4)
DECLARE c_cursor CURSOR FAST_FORWARD FOR SELECT ALMACEN_PEDIDO, CLIENTE, STATUS_PEDIDO FROM INSERTED;
OPEN c_cursor
fetch next from c_cursor into #v_almacen,#v_nombre,#v_status_pedido
--declared and open cursor chargin values to variables
while ##fetch_status = 0
begin
-- set values to variables from anothers tables
set #v_situacion = (select top 1 nombre from dbo.StatusPlanificacion where STATUS_PEDIDO = #v_status_pedido);
set #v_idpla = (select top 1 id from dbo.Planificaciones where dia_entrega >= GETDATE() and
situacion <> 'Departed' and nombre like '%'+#v_almacen +'%'+ #v_nombre);
--check value not null for assigned variable and do update to the value
if(#v_idpla is not null)
begin
UPDATE DBO.Planificaciones
SET situacion = #v_situacion
WHERE id = #v_idpla;
end
--move to the next row of cursor
fetch next from c_cursor into #v_almacen,#v_nombre,#v_status_pedido
end
CLOSE c_cursor
DEALLOCATE c_cursor
end
Not sure if the code is 100% correct but should give you an idea..
inserted is a dataset with all rows of that batch. You just need to think as set based operation.
CREATE TRIGGER TRG_INS_PL_SYNC_STATUS_PLA
ON dbo.pedidos
AFTER INSERT
AS
BEGIN
UPDATE p
SET
situacion = i.nombre
FROM DBO.Planificaciones p
INNER JOIN (
SELECT
v_idpla.id
v_situacion.nombre
FROM INSERTED I
CROSS APPLY (
select top 1
SP.nombre
from dbo.StatusPlanificacion SP
where
SP.STATUS_PEDIDO = I.STATUS_PEDIDO
) v_situacion
CROSS APPLY (
select top 1
Pla.id
from dbo.Planificaciones Pla
where
Pla.dia_entrega >= GETDATE() and
Pla.situacion <> 'Departed' and
Pla.nombre like '%'+I.ALMACEN_PEDIDO +'%'+ I.CLIENTE
) v_idpla
) I ON
P.id = I.id
END

Using fetch next with where in cursor

Is there any option to search inside cursor?
For example: I have a table(MyTable) with row number and value,
that I want to copy to another table(TestTable),
but let's say that if there was a value >= 5 then the next value,
that I want to copy should be <= 3.
I can use something like this:
create table TestTable
(row tinyint,
value tinyint)
declare #row tinyint, #value tinyint, #trigger bit
declare test_cursor cursor fast_forward for
select row,value from MyTable order by row
open test_cursor
fetch next from test_cursor into #row,#value
set #trigger = 0
while ##FETCH_STATUS = 0
begin
if #trigger = 0
begin
insert into TestTable values (#row,#value)
if #value >= 5 set #trigger = 1
end
else if #value <= 3
begin
insert into TestTable values (#row,#value)
set #trigger = 0
end
fetch next from test_cursor into #row,#value
end
close test_cursor
deallocate test_cursor
That will work, but my question is: is there an any way to search inside cursor
for the next falue that <= 3 once trigger = 1,
instead of fetching next row over and over every time?
No, cursors don't support the kind of querying that you're after. You will have to visit each value and check it in the loop.

Resources