Update of column values on condition - sql

I wanted to update the column values on satisfying condition. I wanted the values to 1,2,3,4,5,...
I tried this query but its behaving in a strange way. I'm getting the values starting from 2 i.e 2,3,4,5,..
declare #id int;
set #id = 0;
UPDATE table
SET id = #id + 1, #id = #id + 1
WHERE col4 = 100
AND col5 = 500
AND col3 = 2

It seems like you want to enumerate records that meet the criteria specified in the WHERE clause. I would suggest using a CTE with ROW_NUMBER:
;WITH ToUpdate AS (
SELECT id,
ROW_NUMBER() OVER (ORDER BY col3) AS rn
FROM mytable
WHERE col4=100 AND col5=500 AND col3=2
)
UPDATE ToUpdate
SET id = rn

Try this -
Declare #id int;
Set #id=1;
UPDATE table
SET #id = id = #id + 1
WHERE
(col4=100 AND col5=500 AND col3=2)

Related

Update fetched rows in SQL Server

I have a stored procedure which looks like this:
alter procedure newProcedure
#take int,
#skip int
as
begin
set nocount on
declare #countRowNumbers int;
set #countRowNumbers = (select count(*) from TableA)
select *
from tableA a
order by a.ID
offset ISNULL(#skip,0) rows
fetch next ISNULL(#take, #countRowNumbers) rows only
--update only fetched rows (first 100, or second 100)
-- update TableA set Status = 2
end
I have column status which is representing if the row is under processing or not, so when I grab those 100 documents I need to update that Status status to 2.
How can I do that?
Combining the other answers, using an updatable CTE to carry out the update first, then using the output clause to capture the ID's updated and then select them to return.
declare #SelectedId table (id int);
with toupdate as (
select *
from tableA a
order by a.ID
offset isnull(#skip,0) rows
fetch next isnull(#take, #countRowNumbers) rows only
)
update toupdate
set [status] = 2
output Inserted.id into #SelectedId;
select *
from tableA
where ID in (select id from #SelectedId)
order by ID;
You should be able to use an updatable CTE for this:
with toupdate as (
select *
from tableA a
order by a.ID
offset ISNULL(#skip,0) rows
fetch next ISNULL(#take, #countRowNumbers) rows only
)
update toupdate
set status = 2;
alter procedure newProcedure
#take int,
#skip int
as
begin
set nocount on
declare #countRowNumbers int;
set #countRowNumbers = (select count(*) from TableA)
update tableA set status = 2 where ID in (
select a.ID
from tableA a
order by a.ID
offset ISNULL(#skip,0) rows
fetch next ISNULL(#take, #countRowNumbers) rows only )
--update only fetched rows (first 100, or second 100)
-- update TableA set Status = 2
end

Using ORDER BY command in an UPDATE SQL

I am looking at updating an item number column from a number of rows in a table (which match a particular Product ID & type) but I want to order the rows by numbers in a 'Seqnumber' column then the item number column start at 1 and count each row sequentially by 1.
Using the code below I have been able to select the product id and type I want and update the item number column with sequentially increasing values, however I don't know how I can order the required rows?
DECLARE #id nvarchar(6)
SET #id = 0
UPDATE Table1
SET #id = Table1.ItemNumber = #id + 1
WHERE Product = '5486' AND Table1.Type = 'C'
I know you can't use the ORDER BY command within the UPDATE command without using it as a sub-query. But I'm not sure how I should include this in the above code?
I think I need to incorporate the code below but not sure what the SELECT statement should be and when I try I can't get it to work?
DECALRE #id nvarchar(6)
SET #id = 0
UPDATE Table1
SET #id = TABLE1.ItemNumber = #id + 1
FROM (SELECT TOP (??)* FROM Table1
WHERE Product = '5486' AND Table1.Type ='C'
ORDER BY Table1.SeqNumber ASC
You should be able to build a CTE with the values you want from the table and just update the CTE
declare #Table1 table (Product varchar(4), [Type] varchar(1), SeqNumber int, ItemNumber int)
INSERT INTO #Table1 VALUES
('5486', 'C', 3, 0),
('5486', 'C', 2, 0);
with cte as (
select *,
ROW_NUMBER() OVER (ORDER BY SeqNumber) rn
from #Table1
where Product = '5486' and Type ='C'
)
Update cte
set ItemNumber = rn
This should work:
SET #id = 0;
UPDATE Table1
SET #id = Table1.ItemNumber = (#id := #id + 1)
WHERE Product = 5486 and Table1.Type = 'C'
ORDER BY Table1.seqnumber;
You cannot use ORDER BY with a JOIN, so you need to initialize the variable before the update.
UPDATE sales_data
SET ID = ID + 1
ORDER BY ID DESC;

Subquery in ISNULL,IIF,CASE statements

Subquery that is give as a parameter in ISNULL or IIF or CASE gets executed irrespective of the condition
To explain what I mean, consider the below example. When I run the below query and look in the execution plan, I find that even if the variable #Id not NULL, the second condition gets executed always.
Can anyone explain Why does the subquery gets executed in Query 1,2,3?
--Create a Temp table
IF OBJECT_ID('tempdb..#TempTable') IS NOT NULL DROP TABLE #TempTable
CREATE TABLE #TempTable
(
ID INT
)
--Insert some data
INSERT INTO #TempTable VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(10)
DECLARE #Id INT = 1
--Query 1: ISNULL
SET #Id= ISNULL(#Id, (SELECT TOP 1 ID FROM #TempTable TT WHERE TT.ID = 1))
SELECT #Id AS ID
--Query 2: IIF
SET #Id= IIF(#Id IS NULL,(SELECT TOP 1 ID FROM #TempTable TT WHERE TT.ID = 1),#Id)
SET #Id= IIF(#Id IS NOT NULL,#Id,(SELECT TOP 1 ID FROM #TempTable TT WHERE TT.ID = 1))
SELECT #Id AS ID
--Query 3: CASE
SET #Id= CASE WHEN #Id IS NULL THEN (SELECT TOP 1 ID FROM #TempTable TT WHERE TT.ID = 1) ELSE #Id END
SET #Id= CASE WHEN #Id IS NOT NULL THEN #Id ELSE (SELECT TOP 1 ID FROM #TempTable TT WHERE TT.ID = 1) END
SELECT #Id AS ID
---Query 4: IF
IF #Id IS NULL
BEGIN
SET #Id = (SELECT TOP 1 ID FROM #TempTable TT WHERE TT.ID = 1)
SELECT #Id AS ID
END
ELSE
BEGIN
SELECT #Id AS ID
END
If you want the subquery to execute only when the null condition is met, use an IF instead of ISNULL
if #Id is null
set #id = (SELECT TOP 1 ID FROM #TempTable TT WHERE TT.ID = 1)
instead of
SET #Id= ISNULL(#Id, (SELECT TOP 1 ID FROM #TempTable TT WHERE TT.ID = 1))

SELECT TOP 1, 2, 3 RowId from TableWithNRows

Stupid problem and the answer may not exists (Gasp! Groan! Gnash! Teeth!)
I have a select:
SELECT * FROM SockDrawer WHERE Color = 'red'
This results in 3 rows with row ids of 33896, 35901, 37903
(A lot of other results too.)
What I want is something like this:
DECLARE #ROWID INT --- HOW DO I USE ARRAYS? I'll google but an example would help.
DECLARE #COUNT INT
DECLARE #LIMIT INT
SELECT * FROM SockDrawer WHERE Color = 'red'
--(Returns 3 rows. With 3 RowId's 33896, 35901, 33896)
SET #LIMIT = ##ROWCOUNT
SET #COUNT = 1
WHILE #COUNT < #LIMIT BEGIN
SET #ROWID[0] = (SELECT SockKey From SockDrawer WHERE RowID = 33896)
SET #ROWID[1] = (SELECT SockKey From SockDrawer WHERE RowID = 35901)
SET #ROWID[2] = (SELECT SockKey From SockDrawer WHERE RowID = 33896)
SET #Count = #Count + 1
END
GO
Then I need to:
SET #COUNT = 0
WHILE #COUNT < #LIMIT
BEGIN
DELETE FROM SockDrawer WHERE RowID = #ROWID[#COUNT]
END
GO
The trick is I'll never know if I'm dealing with 1 row to delete or 50.
I'm a dork. I can change. If I want to.
If you don't care about which sock is left for each color, then:
;WITH x AS
(
SELECT *, rn = ROW_NUMBER() OVER (PARTITION BY Color ORDER BY RowID)
FROM dbo.SockDrawer
)
DELETE x WHERE rn > 1;
If you care which one you keep, adjust the ORDER BY accordingly.

Quicker way to update all rows in a SQL Server table

Is there a more efficient way to write this code? Or with less code?
SELECT *
INTO #Temp
FROM testtemplate
Declare #id INT
Declare #name VARCHAR(127)
WHILE (SELECT Count(*) FROM #Temp) > 0
BEGIN
SELECT TOP 1 #id = testtemplateid FROM #Temp
SELECT TOP 1 #name = name FROM #Temp
UPDATE testtemplate
SET testtemplate.vendortestcode = (SELECT test_code FROM test_code_lookup WHERE test_name = #name)
WHERE testtemplateid = #id
--finish processing
DELETE #Temp Where testtemplateid = #id
END
DROP TABLE #Temp
You can do this in a single UPDATE with no need to loop.
UPDATE tt
SET vendortestcode = tcl.test_code
FROM testtemplate tt
INNER JOIN test_code_lookup tcl
ON tt.name = tcl.test_name
You could try a single update like this:
UPDATE A
SET A.vendortestcode = B.test_code
FROM testtemplate A
INNER JOIN test_code_lookup B
ON A.name = B.test_name
Also, the way you are doing it now is wrong, since you are taking a TOP 1 Id and a TOP 1 name in two separate querys, without an ORDER BY, so its not sure that you are taking the right name for your ID.
You could write a function to update vendortestcode. Then your code reduces to one SQL statement:
update testtemplate set vendortestcode = dbo.get_test_code_from_name(name)