Update fetched rows in SQL Server - sql

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

Related

SQL how to update the last row with a where conditon

Update table1 set status='open' where user='test' order by id DESC
i want to update the last row with a where conditon
You can use window function row_number() to get the first row in descending order of id.
with cte as
(
select *,row_number()over(order by id desc)rn from table1
)
Update cte set status='open' where user='test' and rn=1
Or you can use subquery to achieve same result:
UPDATE table1 SET status='open'
WHERE ID=(SELECT MAX(ID)FROM table1 where user='test') and user='test'
In order to find the record you want, you must first find the record you want and then change that record in the table. To do this, you need to create a temporary table and put the desired record in it, then update the table using the information obtained.
--Container to Insert Id which are to be iterated
Declare #temp1 Table
(
ID int
)
--Container to Insert records in the inner select for final output
Insert into #temp1
SELECT top 1 t.id FROM table1 t
WHERE t.user = 'test'
order by t.id desc
-- Keep track of #temp1 record processing
Declare #columnID int
Declare #columnValue varchar(100)
Begin
Set #columnID=(Select Top 1 id From #temp1)
Set #columnValue = 'open'
UPDATE table1 SET status = #columnValue WHERE id = #columnID
Delete #temp1 Where ID=#columnID
End
This should work, presume DBMS is MySQL
UPDATE table1
SET status = "open"
WHERE id in
(SELECT *
FROM
(SELECT id
FROM table1
WHERE USER = "test"
ORDER BY id DESC
LIMIT 1) tmp_tbl);

How to update table column with random value from a list of values?

I am trying to update a table with random values from a specific list of values. I got as far as the code below which does not work because the same value is being inserted into each row:
UPDATE [Post]
SET UserID = (
/** If I run this select statement independently then I get random value each time but not in this update statement **/
SELECT TOP (1) UserID
FROM
[User]
WHERE UserID IN (1,3,4,7)
ORDER BY NEWID()
)
WHERE
UserID <> 10 AND UserID <> 11
I tried looking at using ABS(CHECKSUM(NEWID()))%4 + 5 but generates any number between 1 and 4 which is not what I want. It has to be one of the values of 1,3,4,7 or any other list of specific values.
Demo on db<>fiddle
You can use CROSS APPLY combine with NEWID() to get random value each row being updated
DECLARE #TempTable Table(Id int)
INSERT INTO #TempTable
VALUES(90), (80), (70)
UPDATE t1
SET Id = t2.Id
FROM #TempTable t1
CROSS APPLY (SELECT TOP 1 Id FROM(VALUES(1), (3), (4), (7))t(Id) WHERE t1.Id = t1.Id ORDER BY NEWID()) t2
SELECT * FROM #TempTable
Managed to do it using a CURSOR like this:
DECLARE PostCursor CURSOR
FOR SELECT PostID FROM dbo.Post WHERE UserID <> 10 AND UserID <> 11 FOR UPDATE
OPEN PostCursor
FETCH NEXT FROM PostCursor
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE dbo.Post
SET
UserID = (
SELECT TOP (1) UserID FROM
[dbo].[User]
WHERE UserID IN (1,3,4,7)
ORDER BY NEWID()
)
WHERE CURRENT OF PostCursor
FETCH NEXT FROM PostCursor
END
CLOSE PostCursor
DEALLOCATE PostCursor

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;

Update of column values on condition

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)

Insert rows in table while maintaining IDs

TABLEA
MasterCategoryID MasterCategoryDesc
1 Housing
1 Housing
1 Housing
2 Car
2 Car
2 Car
3 Shop
TABLEB
ID Description
1 Home
2 Home
3 Plane
4 Car
INSERT into TableA
(
[MasterCategoryID]
[MasterCategoryDesc]
)
Select
case when (Description) not in (select MasterCategoryDesc from TableA)
then (select max(MasterCategoryID)+1 from TableA)
else (select top 1 MasterCategoryID from TableA where MasterCategoryDesc = Description)
end as [MasterCategoryID]
,Description as MasterCategoryDesc
from TableB
I want to enter rows using SQL/Stored Procedure from tableB to tableA. for example when inserting first row 'Home' it does not exist in MastercategoryDesc therefore will insert '4' in MasterCategoryID. Second row should keep the '4' again in MasterCategoryID.
The code below does it however after the first row the MastercategoryID remains the same for all rows. I Dont know how to keep track of ids while inserting the new rows.
p.s. Pls do not reply by saying i need to use IDENTITY() index. I have to keep the table structure the same and cannot change it. thanks
Create a new table your_table with fields x_MasterCategoryDesc ,x_SubCategoryDesc
Insert all your values in that table and the run the below SP.
CREATE PROCEDURE x_experiment
AS
BEGIN
IF object_id('TEMPDB..#TABLES') IS NOT NULL
BEGIN
DROP TABLE #TABLES
END
DECLARE #ROWCOUNT INT
DECLARE #ROWINDEX INT =0,
#MasterCategoryDesc VARCHAR(256),
#SubCategoryDesc VARCHAR(256)
select IDENTITY(int,1,1) as ROWID,*
into #TABLES
From your_table
SELECT #ROWCOUNT=COUNT(*) from #TABLES --where ROWID between 51 and 100
WHILE (#ROWINDEX<#ROWCOUNT)
BEGIN
set #ROWINDEX=#ROWINDEX+1
Select
#MasterCategoryDesc=x_MasterCategoryDesc,
#SubCategoryDesc=x_SubCategoryDesc
from #TABLES t
where rowid = #ROWINDEX
INSERT into Table1
([MasterCategoryID], [MasterCategoryDesc], [SubCategoryDesc], [SubCategoryID])
select TOP 1
case when #MasterCategoryDesc not in (select [MasterCategoryDesc] from Table1)
then (select max([MasterCategoryID])+1 from Table1)
else (select distinct max([MasterCategoryID]) from Table1
where [MasterCategoryDesc]=#MasterCategoryDesc
group by [MasterCategoryID])
end as [MasterCategoryID]
,#MasterCategoryDesc as [MasterCategoryDesc]
,#SubCategoryDesc as [SubCategoryDesc]
,case when #SubCategoryDesc not in (select [SubCategoryDesc] from Table1)
then (select max([SubCategoryID])+1 from Table1 )
else (select max([SubCategoryID]) from Table1
where [SubCategoryDesc]=#SubCategoryDesc
group by [SubCategoryID])
end as [SubCategoryID]
from Table1
END
select * from Table1 order by MasterCategoryID
END
GO
exec x_experiment --SP Execute
SQL FIDDLE
Use a CURSOR to do the work. The cursor loops through each row of TableA and the MasterCategoryID increases if it is not found in TableB. This happens before the next row of TableA is loaded into the cursor ...
DECLARE #ID int
DECLARE #Description VARCHAR(MAX)
DECLARE my_cursor CURSOR FOR
SELECT ID, Description FROM TableB
OPEN my_cursor
FETCH NEXT FROM my_cursor
INTO #ID, #Description
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT into TableA(MasterCategoryID, MasterCategoryDesc)
SELECT CASE WHEN #Description NOT IN (SELECT MasterCategoryDesc FROM TableA)
THEN (SELECT MAX(MasterCategoryID)+1 FROM TableA)
ELSE (SELECT TOP 1 MasterCategoryID
FROM TableA
WHERE MasterCategoryDesc = #Description)
END AS MasterCategoryID, Description as MasterCategoryDesc
FROM TableB
WHERE ID = #ID
FETCH NEXT FROM my_cursor
INTO #ID, #Description
END
Your data structure leaves something to be desired. You shouldn't have a master id column that has repeated values.
But you can still do what you want:
INSERT into TableA ([MasterCategoryID], [MasterCategoryDesc])
Select coalesce(a.MasterCategoryId,
amax.maxid + row_number() over (partition by (a.MasterCategoryId) order by b.id)
),
coalesce(a.MasterCategoryDesc, b.desc)
from TableB b left outer join
(select desc, max(MasterCaegoryId) as maxid
from TableA a
group by desc
) a
on b.desc = a.desc left outer join
(select max(MasterCategoryID) as maxid
from TableA
) amax
The idea is to take the information from the master table when it is available. When not available, then MasterCategoryId will be NULL. A new id is calculated, using row_number() to generate sequential numbers. These are then added to the previous maximum id.