query multiple updates - sql

how do I do multiple updates within same query.
Lets say I have this query
UPDATE table1
SET
Order = 1
WHERE
ID = 1234
But I want to change some more orders where IDs are 2345 and 2837 and 8399
how would I do that within same mysql query. Please notice that Order may be different than 1 for those. as order field is unique.

UPDATE table1
SET
Order = 1
WHERE
ID in (2345,2837,8399)

UPDATE table1
SET Order = 1
WHERE id IN (1234, 2345, 2837, 8399)
If you need different values of Order for each id, then you probably want to put a loop in whatever program is talking to the database.
Edited to add
I was thinking of looping in a program, but I see you want to execute the SQL interactively.
If you're trying to bundle a sequence of unpredictable numbers like this:
UPDATE table1 Order = 1 WHERE id = 1234
UPDATE table1 Order = 2 WHERE id = 2345
UPDATE table1 Order = 3 WHERE id = 2837
UPDATE table1 Order = 5 WHERE id = 8399
UPDATE table1 Order = 8 WHERE id = 8675
...then I'm not sure how you want that to be shorter. You can write a stored procedure that gets called like this:
do_table1_update "1,2,3,5,8,13", "1234,2345,2837,8399,8675,309"
Is that what you have in mind?

you can update multiple rows but you can't set the order field to different values, so all order fields (with matching ID) will have the value 1
UPDATE table1 SET Order = 1 WHERE ID IN(1234, 2345, 2837, 8399)

If you want to update the other orders with the same ID of 1, use the IN statement as others have posted. If you don't, use PDO, and a parameterized query.

Related

SQL-Oracle: Updating table multiple row based on values contained in the same table

I have one table named: ORDERS
this table contains OrderNumber's which belong to the same person and same address lines for that person.
However sometimes the data is inconsistent;
as example looking at the table screenshot: Orders table with bad data to fix -
you all can noticed that orderNumber 1 has a name associated to and addresses line1-2-3-4. sometimes those are all different by some character or even null.
my goal is to update all those 3 lines with one set of data that is already there and set equally all the 3 rows.
to make more clear the result expected should be like this:
enter image description here
i am currently using a MERGE statement to avoid a CURSOR (for loop )
but i am having problems to make it work
here the SQL
MERGE INTO ORDERS O USING
(SELECT
INNER.ORDERNUMBER,
INNER.NAME,
INNER.LINE1,
INNER.LINE2,
INNER.LINE3,
INNER.LINE4
FROM ORDERS INNER
) TEMP
ON( O.ORDERNUMBER = TEMP.ORDERNUMBER )
WHEN MATCHED THEN
UPDATE
SET
O.NAME = TEMP.NAME,
O.LINE1 = TEMP.LINE1,
O.LINE2 = TEMP.LINE2,
O.LINE3 = TEMP.LINE3,
O.LINE4 = TEMP.LINE4;
the biggest issues i am facing is to pick a single row out of the 3 randomly - it does not matter whihc of the data - row i pick to update the line/s
as long i make the records exaclty the same for an order number.
i also used ROWNUM =1 but it in multip[le updates will only output one row and update maybe thousand of lines with the same address and name whihch belong to an order number.
order number is the join column to use ...
kind regards
A simple correlated subquery in an update statement should work:
update orders t1
set (t1.name, t1.line1, t1.line2, t1.line3, t1.line4) =
(select t2.name, t2.line1, t2.line2, t2.line3, t2.line4
from orders t2
where t2.OrderNumber = t1.OrderNumber
and rownum < 2)

condition that applies to multiple lines before update is made in another table

I have two tables, one table is linked by a foreign key to the other.
I need to create an update statement that would update table one based on a condition in table two. However, the conditions have to relate to one or more lines in table two.
Example - Table Two
Order A
line 1 = open (status column)
line 2 = closed (staus column)
When line 1 is also closed (same order number - in this case A), the condition is met so the order will then be closed (updated to closed) in the other table. Table on only has header information (no multiple lines).
I am having trouble with righting a condtion that looks at multiple lines in table two (all lines have to be closed) before the update to table one is made.
Any helpful suggestions would be appreciated.
Assuming that (1) the key name is ordernum, and (2) EVERY table1 entry has at least one entry in table2, this is a simple query that should work for you. Basically, the not exists clause is testing that there are no open lines in the second table.
update table1
set table1.status = 'closed'
where table1.status = 'open'
and not exists
(select 1
from table2
where table2.ordernum = table1.ordernum
and table2.status = 'open')
This may need tweaked further based on your business requirements.
Update based on user request: You could try this, but performance may take a hit, I've not tested it:
update table1
set table1.status = 'closed',
table1.count_lines =
(select count(1)
from table2 y
where y.ordernum = table1.ordernum
)
where table1.status = 'open'
and not exists
(select 1
from table2 z
where z.ordernum = table1.ordernum
and z.status = 'open')
Update 2: Try this from your last comment. You are wanting to update the ZORDER table with the sum of all the line item prices. So you must UPDATE ZORDER, not ZORDERLINE. The total is found by summing EXTENDED_PRICE on all ZORDERLINE rows that match the order id. There may be some additional business logic needed in the first sub-query (eg., if you need to exclude certain statuses like canceled items), but this should get you very close.
UPDATE zorder
SET zorder.status = 3,
zorder.total =
(SELECT SUM(Y.EXTENDED_PRICE)
FROM ZORDERLINE Y
WHERE Y.order_id = zorder.order_id)
WHERE zorder.status = 1
and not exists
(select 1
from zorderline z
where z.order_id = zorder.order_id
and z.status = 1)

SQL Server copy contents based on ID

In my DB I have 7 rows for 3 different entities, I want to mirror the contents of one entity to the other two based on an ID value. I do not know if an update statement is appropriate.
CoId DocumentType StatusId StatusDescription Default Text Progression Environment RequiredOnAssign TS DocumentFilterGroup
These are my column headers, CoId can have one of three values, 1, 2, or 3. I wish to copy the contents of 1 into 2 and 3 based on status ID. I have having trouble articulating further than this.
If I understand correctly, then a self-join is your best friend:
UPDATE t1
SET DocumentType = t1.DocumentType, StatusDescription = t1.StatusDescription, Default = t1.Default -- the same for the rest of the fields
FROM table t1
INNER JOIN table t2
ON t1.CoID in (2,3) and t2.CoID = 1
WHERE StatusID = ...

Selecting most recent and specific version in each group of records, for multiple groups

The problem:
I have a table that records data rows in foo. Each time the row is updated, a new row is inserted along with a revision number. The table looks like:
id rev field
1 1 test1
2 1 fsdfs
3 1 jfds
1 2 test2
Note: the last record is a newer version of the first row.
Is there an efficient way to query for the latest version of a record and for a specific version of a record?
For instance, a query for rev=2 would return the 2, 3 and 4th row (not the replaced 1st row though) while a query for rev=1 yields those rows with rev <= 1 and in case of duplicated ids, the one with the higher revision number is chosen (record: 1, 2, 3).
I would not prefer to return the result in an iterative way.
To get only latest revisions:
SELECT * from t t1
WHERE t1.rev =
(SELECT max(rev) FROM t t2 WHERE t2.id = t1.id)
To get a specific revision, in this case 1 (and if an item doesn't have the revision yet the next smallest revision):
SELECT * from foo t1
WHERE t1.rev =
(SELECT max(rev)
FROM foo t2
WHERE t2.id = t1.id
AND t2.rev <= 1)
It might not be the most efficient way to do this, but right now I cannot figure a better way to do this.
Here's an alternative solution that incurs an update cost but is much more efficient for reading the latest data rows as it avoids computing MAX(rev). It also works when you're doing bulk updates of subsets of the table. I needed this pattern to ensure I could efficiently switch to a new data set that was updated via a long running batch update without any windows of time where we had partially updated data visible.
Aging
Replace the rev column with an age column
Create a view of the current latest data with filter: age = 0
To create a new version of your data ...
INSERT: new rows with age = -1 - This was my slow long running batch process.
UPDATE: UPDATE table-name SET age = age + 1 for all rows in the subset. This switches the view to the new latest data (age = 0) and also ages older data in a single transaction.
DELETE: rows having age > N in the subset - Optionally purge old data
Indexing
Create a composite index with age and then id so the view will be nice and fast and can also be used to look up by id. Although this key is effectively unique, its temporarily non-unique when you're ageing the rows (during UPDATE SET age=age+1) so you'll need to make it non-unique and ideally the clustered index. If you need to find all versions of a given id ordered by age, you may need an additional non-unique index on id then age.
Rollback
Finally ... Lets say you're having a bad day and the batch processing breaks. You can quickly revert to a previous data set version by running:
UPDATE table-name SET age = age - 1 -- Roll back a version
DELETE table-name WHERE age < 0 -- Clean up bad stuff
Existing Table
Suppose you have an existing table that now needs to support aging. You can use this pattern by first renaming the existing table, then add the age column and indexing and then create the view that includes the age = 0 condition with the same name as the original table name.
This strategy may or may not work depending on the nature of technology layers that depended on the original table but in many cases swapping a view for a table should drop in just fine.
Notes
I recommend naming the age column to RowAge in order to indicate this pattern is being used, since it's clearer that its a database related value and it complements SQL Server's RowVersion naming convention. It also won't conflict with a column or view that needs to return a person's age.
Unlike other solutions, this pattern works for non SQL Server databases.
If the subsets you're updating are very large then this might not be a good solution as your final transaction will update not just the current records but all past version of the records in this subset (which could even be the entire table!) so you may end up locking the table.
This is how I would do it. ROW_NUMBER() requires SQL Server 2005 or later
Sample data:
DECLARE #foo TABLE (
id int,
rev int,
field nvarchar(10)
)
INSERT #foo VALUES
( 1, 1, 'test1' ),
( 2, 1, 'fdsfs' ),
( 3, 1, 'jfds' ),
( 1, 2, 'test2' )
The query:
DECLARE #desiredRev int
SET #desiredRev = 2
SELECT * FROM (
SELECT
id,
rev,
field,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY rev DESC) rn
FROM #foo WHERE rev <= #desiredRev
) numbered
WHERE rn = 1
The inner SELECT returns all relevant records, and within each id group (that's the PARTITION BY), computes the row number when ordered by descending rev.
The outer SELECT just selects the first member (so, the one with highest rev) from each id group.
Output when #desiredRev = 2 :
id rev field rn
----------- ----------- ---------- --------------------
1 2 test2 1
2 1 fdsfs 1
3 1 jfds 1
Output when #desiredRev = 1 :
id rev field rn
----------- ----------- ---------- --------------------
1 1 test1 1
2 1 fdsfs 1
3 1 jfds 1
If you want all the latest revisions of each field, you can use
SELECT C.rev, C.fields FROM (
SELECT MAX(A.rev) AS rev, A.id
FROM yourtable A
GROUP BY A.id)
AS B
INNER JOIN yourtable C
ON B.id = C.id AND B.rev = C.rev
In the case of your example, that would return
rev field
1 fsdfs
1 jfds
2 test2
SELECT
MaxRevs.id,
revision.field
FROM
(SELECT
id,
MAX(rev) AS MaxRev
FROM revision
GROUP BY id
) MaxRevs
INNER JOIN revision
ON MaxRevs.id = revision.id AND MaxRevs.MaxRev = revision.rev
SELECT foo.* from foo
left join foo as later
on foo.id=later.id and later.rev>foo.rev
where later.id is null;
How about this?
select id, max(rev), field from foo group by id
For querying specific revision e.g. revision 1,
select id, max(rev), field from foo where rev <= 1 group by id

How to get one common value from Database using UNION

2 records in above image are from Db, in above table Constraint are (SID and LINE_ITEM_ID),
SID and LINE_ITEM_ID both column are used to find a unique record.
My issues :
I am looking for a query it should fetch the recored from DB depending on conditions
if i search for PART_NUMBER = 'PAU43-IMB-P6'
1. it should fetch one record from DB if search for PART_NUMBER = 'PAU43-IMB-P6', no mater to which SID that item belong to if there is only one recored either under SID =1 or SID = 2.
2. it should fetch one record which is under SID = 2 only, from DB on search for PART_NUMBER = 'PAU43-IMB-P6', if there are 2 items one in SID=1 and other in SID=2.
i am looking for a query which will search for a given part_number depending on Both SID 1 and 2, and it should return value under SID =2 and it can return value under SID=1 only if the there are no records under SID=2 (query has to withstand a load of Million record search).
Thank you
Select *
from Table
where SID||LINE_ITEM_ID = (
select Max(SID)||Max(LINE_ITEM_ID)
from table
where PART_NUMBER = 'PAU43-IMB-P6'
);
If I understand correctly, for each considered LINE_ITEM_ID you want to return only the one with the largest value for SID. This is a common requirement and, as with most things in SQL, can be written in many different ways; the best performing will depend on many factors, not least of which is the SQL product you are using.
Here's one possible approach:
SELECT DISTINCT * -- use a column list
FROM YourTable AS T1
INNER JOIN (
SELECT T2.LINE_ITEM_ID,
MAX(T2.SID) AS max_SID
FROM YourTable AS T2
GROUP
BY T2.LINE_ITEM_ID
) AS DT1 (LINE_ITEM_ID, max_SID)
ON T1.LINE_ITEM_ID = DT1.LINE_ITEM_ID
AND T1.SID = DT1.max_SID;
That said, I don't recall seeing one that relies on the UNION relational operator. You could easily rewrite the above using the INTERSECT relational operator but it would be more verbose.
Well in my case it worked something like this:
select LINE_ITEM_ID,SID,price_1,part_number from (
(select LINE_ITEM_ID,SID,price_1,part_number from Table where SID = 2)
UNION
(select LINE_ITEM_ID,SID,price_1,part_number from Table SID = 1 and line_item_id NOT IN (select LINE_ITEM_ID,SID,price_1,part_number from Table SID = 2)))
This query solved my issue..........