Select and update; SQL Server - sql-server

I need to loop table tab_A entry by entry and update table tab_B according to content in each returned entry:
SELECT item, regBy, MAX(regTime) AS latestUpdateTime
FROM tab_A
GROUP BY item, regBy;
The result must be looped entry by entry and the following UPDATE must be performed for each entry:
UPDATE tab_B
SET lastUpdated = "data from latestUpdateTime in SQL above"
lastUpdBy = "data from regBy in SQL above"
WHERE item = "data from item in SQL above"
I'm not familiar with Transact SQL, so any help would be appreciated.

You can turn a regular select statement into an update statement quite easily by replacing the SELECT * with UPDATE table...
This allows you to first verify what will get updated before actually applying the update.
Select statement
SELECT *
FROM tab_B b
INNER JOIN (
SELECT item
, regBy
, MAX(regTime) AS latestUpdateTime
FROM tab_A
GROUP BY
item
, regBy
) a ON a.item = b.item
Update statement
UPDATE tab_B
SET lastUpdated = a.latestUpdateTime
, lastUpdBy = a.regBy
FROM tab_B b
INNER JOIN (
SELECT item
, regBy
, MAX(regTime) AS latestUpdateTime
FROM tab_A
GROUP BY
item
, regBy
) a ON a.item = b.item
Another way to verify the update and depending on your version would be by starting a transaction and using the OUTPUT clause.
BEGIN TRAN
UPDATE tab_B
SET lastUpdated = a.latestUpdateTime
, lastUpdBy = a.regBy
OUTPUT INSERTED.*
FROM tab_B b
INNER JOIN (
SELECT item
, regBy
, MAX(regTime) AS latestUpdateTime
FROM tab_A
GROUP BY
item
, regBy
) a ON a.item = b.item
ROLLBACK TRAN

If you're using SQL Server 2005 or newer, you can do something like this:
;WITH TableAData AS
(
SELECT
item, regBy, regTime,
RowNum = ROW_NUMBER() OVER(PARTITION BY item ORDER BY regTime DESC)
FROM dbo.tab_A
)
UPDATE dbo.tab_B
SET
lastUpdated = a.regTime,
lastUpdBy = a.regby
FROM TableAData a
WHERE
tab_B.item = a.item
AND a.RowNum = 1
Basically, this CTE (Common Table Expression) orders your data in such a way that for each item, a RowNum is calculated (with the most recent one getting RowNum = 1).
With this, you can easily update your tab_B in a single statement - no row-by-agonizing-row looping needed!

Related

SQL update from a row found from another column's value [duplicate]

I have to update a field with a value which is returned by a join of 3 tables.
Example:
select
im.itemid
,im.sku as iSku
,gm.SKU as GSKU
,mm.ManufacturerId as ManuId
,mm.ManufacturerName
,im.mf_item_number
,mm.ManufacturerID
from
item_master im, group_master gm, Manufacturer_Master mm
where
im.mf_item_number like 'STA%'
and im.sku=gm.sku
and gm.ManufacturerID = mm.ManufacturerID
and gm.manufacturerID=34
I want to update the mf_item_number field values of table item_master with some other value which is joined in the above condition.
How can I do this in MS SQL Server?
UPDATE im
SET mf_item_number = gm.SKU --etc
FROM item_master im
JOIN group_master gm
ON im.sku = gm.sku
JOIN Manufacturer_Master mm
ON gm.ManufacturerID = mm.ManufacturerID
WHERE im.mf_item_number like 'STA%' AND
gm.manufacturerID = 34
To make it clear... The UPDATE clause can refer to an table alias specified in the FROM clause. So im in this case is valid
Generic example
UPDATE A
SET foo = B.bar
FROM TableA A
JOIN TableB B
ON A.col1 = B.colx
WHERE ...
Adapting this to MySQL -- there is no FROM clause in UPDATE, but this works:
UPDATE
item_master im
JOIN
group_master gm ON im.sku=gm.sku
JOIN
Manufacturer_Master mm ON gm.ManufacturerID=mm.ManufacturerID
SET
im.mf_item_number = gm.SKU --etc
WHERE
im.mf_item_number like 'STA%'
AND
gm.manufacturerID=34
One of the easiest way is to use a common table expression (since you're already on SQL 2005):
with cte as (
select
im.itemid
,im.sku as iSku
,gm.SKU as GSKU
,mm.ManufacturerId as ManuId
,mm.ManufacturerName
,im.mf_item_number
,mm.ManufacturerID
, <your other field>
from
item_master im, group_master gm, Manufacturer_Master mm
where
im.mf_item_number like 'STA%'
and im.sku=gm.sku
and gm.ManufacturerID = mm.ManufacturerID
and gm.manufacturerID=34)
update cte set mf_item_number = <your other field>
The query execution engine will figure out on its own how to update the record.
Did not use your sql above but here is an example of updating a table based on a join statement.
UPDATE p
SET p.category = c.category
FROM products p
INNER JOIN prodductcatagories pg
ON p.productid = pg.productid
INNER JOIN categories c
ON pg.categoryid = c.cateogryid
WHERE c.categories LIKE 'whole%'
You can specify additional tables used in determining how and what to update with the "FROM " clause in the UPDATE statement, like this:
update item_master
set mf_item_number = (some value)
from
group_master as gm
join Manufacturar_Master as mm ON ........
where
.... (your conditions here)
In the WHERE clause, you need to provide the conditions and join operations to bind these tables together.
Marc
MySQL: In general, make necessary changes par your requirement:
UPDATE
shopping_cart sc
LEFT JOIN
package pc ON sc. package_id = pc.id
SET
sc. amount = pc.amount
It is very simple to update using join query in SQL .You can do it without using FROM clause. Here is an example :
UPDATE customer_table c
JOIN
employee_table e
ON c.city_id = e.city_id
JOIN
anyother_ table a
ON a.someID = e.someID
SET c.active = "Yes"
WHERE c.city = "New york";
You can use the following query:
UPDATE im
SET mf_item_number = (some value)
FROM item_master im
JOIN group_master gm
ON im.sku = gm.sku
JOIN Manufacturer_Master mm
ON gm.ManufacturerID = mm.ManufacturerID
WHERE im.mf_item_number like 'STA%' AND
gm.manufacturerID = 34 `sql`
Try like this...
Update t1.Column1 = value
from tbltemp as t1
inner join tblUser as t2 on t2.ID = t1.UserID
where t1.[column1]=value and t2.[Column1] = value;
If you are using SQL Server you can update one table from other table without specifying a join and simply link the two tables from the where clause. This makes a much simpler SQL query:
UPDATE Table1
SET Table1.col1 = Table2.col1,
Table1.col2 = Table2.col2
FROM
Table2
WHERE
Table1.id = Table2.id
You can update with MERGE Command with much more control over MATCHED and NOT MATCHED:(I slightly changed the source code to demonstrate my point)
USE tempdb;
GO
IF(OBJECT_ID('target') > 0)DROP TABLE dbo.target
IF(OBJECT_ID('source') > 0)DROP TABLE dbo.source
CREATE TABLE dbo.Target
(
EmployeeID INT ,
EmployeeName VARCHAR(100) ,
CONSTRAINT Target_PK PRIMARY KEY ( EmployeeID )
);
CREATE TABLE dbo.Source
(
EmployeeID INT ,
EmployeeName VARCHAR(100) ,
CONSTRAINT Source_PK PRIMARY KEY ( EmployeeID )
);
GO
INSERT dbo.Target
( EmployeeID, EmployeeName )
VALUES ( 100, 'Mary' );
INSERT dbo.Target
( EmployeeID, EmployeeName )
VALUES ( 101, 'Sara' );
INSERT dbo.Target
( EmployeeID, EmployeeName )
VALUES ( 102, 'Stefano' );
GO
INSERT dbo.Source
( EmployeeID, EmployeeName )
VALUES ( 100, 'Bob' );
INSERT dbo.Source
( EmployeeID, EmployeeName )
VALUES ( 104, 'Steve' );
GO
SELECT * FROM dbo.Source
SELECT * FROM dbo.Target
MERGE Target AS T
USING Source AS S
ON ( T.EmployeeID = S.EmployeeID )
WHEN MATCHED THEN
UPDATE SET T.EmployeeName = S.EmployeeName + '[Updated]';
GO
SELECT '-------After Merge----------'
SELECT * FROM dbo.Source
SELECT * FROM dbo.Target
Let me just add a warning to all the existing answers:
When using the SELECT ... FROM syntax, you should keep in mind that it is proprietary syntax for T-SQL and is non-deterministic. The worst part is, that you get no warning or error, it just executes smoothly.
Full explanation with example is in the documentation:
Use caution when specifying the FROM clause to provide the criteria for the update operation. The results of an UPDATE statement are undefined if the statement includes a FROM clause that is not specified in such a way that only one value is available for each column occurrence that is updated, that is if the UPDATE statement is not deterministic.
I've been trying to do things like this forever and it just occurred to me to try using the following syntax (using tuples)
update dstTable T
set (T.field1, T.field2, T.field3) =
(select S.value1, S.value2, S.value3
from srcTable S
where S.key = T.Key);
And surprisingly it worked. I'm using Oracle (12c I think). Is this standard SQL or Oracle specific?
NB: In my example I'm updating the entire table (filling new columns). The update has no where clause so all rows will be updated. Your fields will be set to NULL when the subquery doesn't return a row. (and it must not return more than one row).

Simple SQLite UPDATE Statement does not work

I inserted a new column in my database and want to populate with data. It shall be calculated from the difference of the value of nom_arr_time and the value of nom_dep_time of the previous row.
If I try to execute the SELECT statement only everything works fine. But the update won't work, the column stays empty.
UPDATE mobile_statistik
SET nom_fahrzeit = (SELECT nom_arr_time - LAG(nom_dep_time,1,0) OVER (ORDER BY id)
FROM mobile_statistik);
Handling the task through a programming language like python is not an option because of the size, ca. 20GB of the database.
You can do it like this:
UPDATE mobile_statistik
SET nom_fahrzeit = (
SELECT t.nom_arr_time - t.prev FROM (
SELECT id, nom_arr_time, LAG(nom_dep_time,1,0) OVER (ORDER BY id) prev
FROM mobile_statistik
) t
WHERE t.id = mobile_statistik.id
)
or without LAG():
UPDATE mobile_statistik
SET nom_fahrzeit =
nom_arr_time - (
SELECT m.nom_dep_time
FROM mobile_statistik m
WHERE m.id = (SELECT MAX(t.id) FROM mobile_statistik t WHERE t.id < mobile_statistik.id)
);

I want to update one table data based on the join condition with another table in SQL server

I tried to update a column in one table from another table using join condition. I tried all possible ways and its showing SQL command not properly ended.I am trying t his in sql server.
update a
set a.col4=b.col4
from dummy_jd a
join --select * from dummy_jd a,
(select col1,col2,col3,col4,col5,sum(reported_amount) reported_amount
from dummy_jd_2
where col5=3843
and col3='abc'
and col1=4
and col2=3002
group by col1,col2,col3,col4,col5
) b on (a.col2=b.col5 and a.col4=b.col3)
where a.col1=9;
This is which i tried
Try below -
update a set a.col4=b.col4 from dummy_jd a
join
(select col1,col2,col3,col4,col5,sum(reported_amount) reported_amount
from dummy_jd_2 where col5=3843 and col3='abc' and col1=4 and col2=3002
group by col1,col2,col3,col4,col5
)b on a.col2=b.col5 and a.col4=b.col3
where a.col1=9
Thanks to everyone i achieved it by using for loopand joins below is the query i used
for i in (select * from dummy_jd1)
loop
update dummy_jd a set a.col4 = (select distinct col4 from dummy_jd_2 b
where /*(jnl_ref_no, bill_ref_no) in (select
jnl_ref_no,bill_ref_no from dummy_jd1) and*/
a.col2 = b.col5
and a.col4 = b.col3
and b.col5 = i.col2
and b.col3 = i.col3
and id_type = 4
--and id_value in(3002,3019)
and reported_amount <> 0
group by col1,col2,col3,col4,col5)
where a.id_type = 9
and a.col2=i.col2
and a.col4=i.col3;

Updating DISTINCTROW in SQL Server [duplicate]

What would the syntax be to convert this MS Access query to run in SQL Server as it doesn't have a DistinctRow keyword
UPDATE DISTINCTROW [MyTable]
INNER JOIN [AnotherTable] ON ([MyTable].J5BINB = [AnotherTable].GKBINB)
AND ([MyTable].J5BHNB = [AnotherTable].GKBHNB)
AND ([MyTable].J5BDCD = [AnotherTable].GKBDCD)
SET [AnotherTable].TessereCorso = [MyTable].[J5F7NR];
DISTINCTROW [MyTable] removes duplicate MyTable entries from the results. Example:
select distinctrow items
items.item_number, items.name
from items
join orders on orders.item_id = items.id;
In spite of the join getting you the same item_number and name multiple times when there is more than one order for it, DISTINCTROW reduces this to one row per item. So the whole join is merely for assuring that you only select items for which exist at least one order. You don't find DISTINCTROW in any other DBMS as far as I know. Probably because it is not needed. When checking for existence, we use EXISTS of course (or IN for that matter).
You are joining MyTable and AnotherTable and expect for some reason to get the same MyTable record multifold for one AnotherTable record, so you use DISTINCTROW to only get it once. Your query would (hopefully) fail if you got two different MyTable records for one AnotherTable record.
What the update does is:
update anothertable
set tesserecorso = (select top 1 j5f7nr from mytable where mytable.j5binb = anothertable.gkbinb and ...)
where exists (select * from mytable where mytable.j5binb = anothertable.gkbinb and ...)
But this uses about the same subquery twice. So we'd want to update from a query instead.
The easiest way to get one result record per <some columns> in a standard SQL query is to aggregate data:
select *
from anothertable a
join
(
select j5binb, j5bhnb, j5bdcd, max(j5f7nr) as j5f7nr
from mytable
group by j5binb, j5bhnb, j5bdcd
) m on m.j5binb = a.gkbinb and m.j5bhnb = a.gkbhnb and m.j5bdcd = a.gkbdcd;
How to write an updateble query is different from one DBMS to another. Here is the final update statement for SQL-Server:
update a
set a.tesserecorso = m.j5f7nr
from anothertable a
join
(
select j5binb, j5bhnb, j5bdcd, max(j5f7nr) as j5f7nr
from mytable
group by j5binb, j5bhnb, j5bdcd
) m on m.j5binb = a.gkbinb and m.j5bhnb = a.gkbhnb and m.j5bdcd = a.gkbdcd;
The DISTINCTROW predicate in MS Access SQL removes duplicates across all fields of a table in join statements and not just the selected fields of query (which DISTINCT in practically all SQL dialects do). So consider selecting all fields in a derived table with DISTINCT predicate:
UPDATE [AnotherTable]
SET [AnotherTable].TessereCorso = main.[J5F7NR]
FROM
(SELECT DISTINCT m.* FROM [MyTable] m) As main
INNER JOIN [AnotherTable]
ON (main.J5BINB = [AnotherTable].GKBINB)
AND (main.J5BHNB = [AnotherTable].GKBHNB)
AND (main.J5BDCD = [AnotherTable].GKBDCD)
Another variant of the query.. (Too lazy to get the original tables).
But like the query above updates 35 rows =, so does this one
UPDATE [Albi-Anagrafe-Associati]
SET
[Albi-Anagrafe-Associati].CRegDitte = [055- Registri ditte].[CRegDitte],
[Albi-Anagrafe-Associati].NIscrTribunale = [055- Registri ditte].[NIscrTribunale],
[Albi-Anagrafe-Associati].NRegImprese = [055- Registri ditte].[NRegImprese]
FROM [055- Registri ditte]
WHERE EXISTS(
SELECT *
FROM [055- Registri ditte]-- [Albi-Anagrafe-Associati]
WHERE ([055- Registri ditte].GIBINB = [Albi-Anagrafe-Associati].GKBINB)
AND ([055- Registri ditte].GIBHNB = [Albi-Anagrafe-Associati].GKBHNB)
AND ([055- Registri ditte].GIBDCD = [Albi-Anagrafe-Associati].GKBDCD))
Update [AnotherTable]
Set [AnotherTable].TessereCorso = MyTable.[J5F7NR]
From [AnotherTable]
Inner Join
(
Select Distinct [J5BINB],[5BHNB],[J5BDCD]
,(Select Top 1 [J5F7NR] From MyTable) as [J5F7NR]
,[J5BHNB]
From MyTable
)as MyTable
On (MyTable.J5BINB = [AnotherTable].GKBINB)
AND (MyTable.J5BHNB = [AnotherTable].GKBHNB)
AND (MyTable.J5BDCD = [AnotherTable].GKBDCD)

SQL Update query using select statement

I am trying to update a column in a table where the another column matches and selecting the top 1 for that column as the value to update.
Hard to explain, but this is what I wrote:
UPDATE CameraSpecifications AS a
SET a.Variant = (
SELECT TOP 1 GTIN
FROM CameraSpecifcations
WHERE b.ModelGroup = a.ModelGroup )
Hopefully that explains what I am trying to do.
I have a select statement that might also help:
SELECT
(
SELECT TOP 1 b.GTIN
FROM CameraSpecifications AS b
WHERE b.ModelGroup = a.ModelGroup
) AS Gtin,
a.ModelGroup,
COUNT(a.ModelGroup)
FROM CameraSpecifications AS a
GROUP BY a.ModelGroup
We can try doing an update join from CameraSpecifications to a CTE which finds the top GTIN value for each model group. Note carefully that I use an ORDER BY clause in ROW_NUMBER. It makes no sense to use TOP 1 without ORDER BY, so you should at some point update your question and mention TOP 1 with regard to a certain column.
WITH cte AS (
SELECT ModelGroup, GTIN,
ROW_NUMBER() OVER (PARTITION BY ModelGroup ORDER BY some_col) rn
FROM CameraSpecifications
)
UPDATE cs
SET Variant = t.GTIN
FROM CameraSpecifcations cs
INNER JOIN cte t
ON cs.ModelGroup = t.ModelGroup
WHERE
t.rn = 1;

Resources