SQL how to update the last row with a where conditon - sql

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);

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

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;

Loop through sql result set and remove [n] duplicates

I've got a SQL Server db with quite a few dupes in it. Removing the dupes manually is just not going to be fun, so I was wondering if there is any sort of sql programming or scripting I can do to automate it.
Below is my query that returns the ID and the Code of the duplicates.
select a.ID, a.Code
from Table1 a
inner join (
SELECT Code
FROM Table1 GROUP BY Code HAVING COUNT(Code)>1)
x on x.Code= a.Code
I'll get a return like this, for example:
5163 51727
5164 51727
5165 51727
5166 51728
5167 51728
5168 51728
This snippet shows three returns for each ID/Code (so a primary "good" record and two dupes). However this isnt always the case. There can be up to [n] dupes, although 2-3 seems to be the norm.
I just want to somehow loop through this result set and delete everything but one record. THE RECORDS TO DELETE ARE ARBITRARY, as any of them can be "kept".
You can use row_number to drive your delete.
ie
CREATE TABLE #table1
(id INT,
code int
);
WITH cte AS
(select a.ID, a.Code, ROW_NUMBER() OVER(PARTITION by COdE ORDER BY ID) AS rn
from #Table1 a
)
DELETE x
FROM #table1 x
JOIN cte ON x.id = cte.id
WHERE cte.rn > 1
But...
If you are going to be doing a lot of deletes from a very large table you might be better off to select out the rows you need into a temp table & then truncate your table and re-insert the rows you need.
Keeps the Transaction log from getting hammered, your CI getting Fragged and should be quicker too!
It is actually very simple:
DELETE FROM Table1
WHERE ID NOT IN
(SELECT MAX(ID)
FROM Table1
GROUP BY CODE)
Self join solution with a performance test VS cte.
create table codes(
id int IDENTITY(1,1) NOT NULL,
code int null,
CONSTRAINT [PK_codes_id] PRIMARY KEY CLUSTERED
(
id ASC
))
declare #counter int, #code int
set #counter = 1
set #code = 1
while (#counter <= 1000000)
begin
print ABS(Checksum(NewID()) % 1000)
insert into codes(code) select ABS(Checksum(NewID()) % 1000)
set #counter = #counter + 1
end
GO
set statistics time on;
delete a
from codes a left join(
select MIN(id) as id from codes
group by code) b
on a.id = b.id
where b.id is null
set statistics time off;
--set statistics time on;
-- WITH cte AS
-- (select a.id, a.code, ROW_NUMBER() OVER(PARTITION by code ORDER BY id) AS rn
-- from codes a
-- )
-- delete x
-- FROM codes x
-- JOIN cte ON x.id = cte.id
-- WHERE cte.rn > 1
--set statistics time off;
Performance test results:
With Join:
SQL Server Execution Times:
CPU time = 3198 ms, elapsed time = 3200 ms.
(999000 row(s) affected)
With CTE:
SQL Server Execution Times:
CPU time = 4197 ms, elapsed time = 4229 ms.
(999000 row(s) affected)
It's basically done like this:
WITH CTE_Dup AS
(
SELECT*,
ROW_NUMBER()OVER (PARTITIONBY SalesOrderno, ItemNo ORDER BY SalesOrderno, ItemNo)
AS ROW_NO
from dbo.SalesOrderDetails
)
DELETEFROM CTE_Dup WHERE ROW_NO > 1;
NOTICE: MUST INCLUDE ALL FIELDS!!
Here is another example:
CREATE TABLE #Table (C1 INT,C2 VARCHAR(10))
INSERT INTO #Table VALUES (1,'SQL Server')
INSERT INTO #Table VALUES (1,'SQL Server')
INSERT INTO #Table VALUES (2,'Oracle')
SELECT * FROM #Table
;WITH Delete_Duplicate_Row_cte
AS (SELECT ROW_NUMBER()OVER(PARTITION BY C1, C2 ORDER BY C1,C2) ROW_NUM,*
FROM #Table )
DELETE FROM Delete_Duplicate_Row_cte WHERE ROW_NUM > 1
SELECT * FROM #Table

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.