Home > Software engineering >  Update table with nearest value
Update table with nearest value

Time:06-29

I have a SQL table with Postal Codes like this:

Postal code City
10001 New York
33101 Miami
94016 San Francisco

And another table, like this:

Client Postal code
Adam 33000

I need a query that updates the second table with the nearest postal code (from the first table). The result should be:

Client Postal code
Adam 33101

CodePudding user response:

Try the following:

with cte as(
Select A.Postal_Code As UpdateTo,B.Postal_Code As ToBeUpdated, 
Row_Number() Over (Partition By B.Postal_Code Order By Abs(A.Postal_Code-B.Postal_Code)) as rn
From Postals A , Clients B 
)

Update Clients C Set C.Postal_Code = (Select D.UpdateTo From cte D 
                                      where C.Postal_Code=D.ToBeUpdated and D.rn=1);
select * from Clients

See a demo from db-fiddle.

CodePudding user response:

update Table2
set PostalCode = (
    select top 1 t1.PostalCode
    from Table1 t1
    /* optionally improve the lookup by requiring first two digits to match */
    where t1.PostalCode like left(Table2.PostalCode, 2)   '%'
    order by
        abs(cast(t1.PostalCode as int) - cast(Table2.PostalCode as int)),
        t1.PostalCode /* ties go low */
)
where not exists (
    select 1 from Table1 t1 where t1.PostalCode = Table2.PostalCode
)

This is generic SQL with these requirements: There's an absolute value function, that string concatenation is (try || if not), that you have top 1 or limit 1 available, that postal codes are stored as strings that easily convert to integer.

https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=a7e0383ff6c23d7fc33070066a4abaa3

Here's a version that might be appropriate for SQL Server specifically. It does separate searches for next lower and next higher values. Depending on the indexing it could be the more efficient approach.

/* more complicated but possibly a better plan */
update c
set PostalCode = case when abs(Code - Code1) <= abs(Code - Code2)
                      then Code1 else coalesce(Code2, Code1) end /* ties go low */
from Clients c
    cross apply (values (cast(PostalCode as int))) z0(Code) cross apply (
    select min(PostalCode), cast(min(PostalCode) as int) from Zips z
    where z.PostalCode > c.PostalCode
) z1(PostalCode1, Code1) cross apply (
    select max(PostalCode), cast(min(PostalCode) as int) from Zips z
    where z.PostalCode < c.PostalCode
) z2(PostalCode2, Code2)
where not exists (
    select 1 from Zips z where z.PostalCode = c.PostalCode
);
  •  Tags:  
  • sql
  • Related