Home > Mobile >  SQL query to update a record based on the max value in another column
SQL query to update a record based on the max value in another column

Time:06-11

The Problem

I have this table. (You can also view it in DBFiddle.)

Id Version Item No. Notes
1 NULL 31
2 1 31 tasty
3 2 31 kinda tasty
4 NULL 32
5 1 32 meh
6 2 32 alright
7 3 32 fabulous
8 NULL 33 ambivalent
9 1 33 gross
10 2 33 puke

The 1st column is the primary key. The 2nd and 3rd column are integers. The 4th column is a VARCHAR.

For every unique Item No. where its Version is NULL, I want to look at the record with the highest Version value, take the content of its Notes field, and copy it over.

This is much easier to understand visually; after the command is run, the table should look like this:

Id Version Item No. Notes
1 NULL 31 kinda tasty
2 1 31 tasty
3 2 31 kinda tasty
4 NULL 32 fabulous
5 1 32 meh
6 2 32 alright
7 3 32 fabulous
8 NULL 33 ambivalent
9 1 33 gross
10 2 33 puke

Explanation of the Changes

  • for Item No. 31, "kinda tasty" was copied over because it's in the record with the highest Version number, and the target cell is not occupied.
  • for Item No. 32, "fabulous" was copied over for the same reason.
  • "puke" was NOT copied over to replace "ambivalent", because the target cell is occupied.

The Question

What is the query to achieve this in SQL Server?

I know that I need a way of grouping records together by Item No., find the one with the highest Version value, take its Notes value, and copy it to the record where the Version is NULL, but I am having trouble translating this to SQL.

CodePudding user response:

Try this:

UPDATE t SET notes = (
   SELECT TOP 1 s.notes 
   FROM t s 
   WHERE s.item_no = t.item_no 
   ORDER BY version DESC
) WHERE version IS NULL AND notes IS NULL

Check demo

CodePudding user response:

Use an updatable CTE:

WITH cte AS (
  SELECT *, FIRST_VALUE(Notes) OVER (PARTITION BY ItemNo ORDER BY Version DESC) newNotes 
  FROM tablename
)
UPDATE cte
SET Notes = newNotes
WHERE Version IS NULL AND Notes IS NULL;

See the demo.

CodePudding user response:

Create a CTE to determine the value we need to update to, and then join that to your original table with update join syntax:

with maxVal as
(
    select row_number() over (partition by [Item No.] order by Version desc) rn
        , notes
        , [Item No.]
    from TestTable
    where Version is not null
)
update TestTable
set Notes = maxVal.Notes
from TestTable
left join maxVal
    on TestTable.[Item No.] = maxVal.[Item No.]
    and maxVal.rn = 1
where TestTable.Version is null
    and TestTable.Notes = ''

CodePudding user response:

You can try that appraoch :

-- Preparing a table variable
DECLARE @table1 AS TABLE (
    id  INT IDENTITY(1,1) NOT NULL,
    VersionID INT,
    ItemNo INT,
    Note Varchar(50)
)

insert into 
    @table1 (VersionID,ItemNo,Note)
values 
    (NULL,31,''),
    (1,31,'tasty'),
    (2,31,'kinda tasty'),
    (NULL,32,''),
    (1,32,'meh'),
    (2,32,'alright'),
    (3,32,'fabulous'),
    (NULL,33,'ambivalent'),
    (1,33,'gross'),
    (2,33,'puke');

-- update section 
update up set up.Note = db.Note
from @table1 up
inner join 
(
    select a.ItemNo,a.Note
    from @table1 a
    inner join 
    (
        select itemNo,Max(VersionID) as vs
        from @table1
        where Note <> ''
        group by itemNo
    ) as b on a.ItemNo = b.ItemNo and a.VersionID = b.vs
) as db on db.ItemNo = up.ItemNo and up.Note = ''


-- result
select * from @table1

CodePudding user response:

You can select the maximum value for each "Item No.", then update the original table with the corresponding value where the "Notes" is NULL.

UPDATE tab 
SET [Notes] = t2.[Notes]
FROM       tab t1 
INNER JOIN (SELECT *, MAX(Version) OVER(PARTITION BY [Item No.]) AS Max_Version
            FROM tab)  t2
        ON t1.[Item No.] = t2.[Item No.]
       AND t2.[Version]  = t2.[Max_Version]
       AND t1.[Notes] IS NULL

Check the demo here.

  • Related