Multi update query - sql

I've created two temp tables. One with Orders which contains Article and Quantity and the other one with availability where we also have Article and Quantity. I would like to write a multi update query with subtracking order quantity from stock and from itself for all articles in temporary table with Orders. As far as I know it is not possible to alter two fields from different tables in one update query.
I've tried something like this, but it's of course doesn't work.
UPDATE #Stocks as s
INNER JOIN #Orders as o on o.ArticleId=s.ArticleId
SET
s.Quantity = (s.Quantity - o.Quanity)
FROM
#Stocks s
JOIN #Orders o on o.ArticleId=s.ArticleId
WHERE
#Stocks.ArticleId IN (SELECT ArticleId FROM #Orders)

When do you an update using a join with multiple matches, only one arbitrary row is chosen for the update. The key idea is to aggregate the data before the update:
UPDATE s
SET Quantity = (s.Quantity - o.Quanity)
FROM #Stocks s JOIN
(SELECT o.ArticleId, SUM(o.Quantity) as quantity
FROM #Orders o
GROUP BY o.ArticleId
) o
ON o.ArticleId = s.ArticleId;
Your statement is way over-complicated, mixing update syntax from SQL Server, MySQL, and Postgres. In addition, the WHERE clause is unnecessary because the JOIN does the filtering. However, even once the syntax errors are fixed, you will still have the problem of calculating incorrect results, unless you pre-aggregate the data.
Unfortunately, the description of this behavior is buried deep in the documentation of the first example on the update page:
The previous example assumes that only one sale is recorded for a
specified salesperson on a specific date and that updates are current.
If more than one sale for a specified salesperson can be recorded on
the same day, the example shown does not work correctly. The example
runs without error, but each SalesYTD value is updated with only one
sale, regardless of how many sales actually occurred on that day. This
is because a single UPDATE statement never updates the same row two
times. [emphasis added]

How about this?
UPDATE s
SET s.Quantity = (s.Quantity - o.Quanity)
FROM #Stocks as s
INNER JOIN #Orders as o on o.ArticleId=s.ArticleId

For updating two tables using single query, you should create a view that contain both tables columns and then update that view.

Your Question is all about Multi Update,
but updation perform in one table based on another table so
to do this use join
But if updation perform in two or more table we have to create view then we can update
thanks

Related

How to use not in / not like to compare values from different tables in SQL

I have SQL 2019 with these two tables - Orders and Customers with respective columns
id,order_comment,customer_id
in Orders and
id,customer_name
in Customers. Order_comment is ntext type.
I need to update the order_comment with customer_name value.
The update should be something like this:
update o set order_comment=concat(c.customer_name,';',o.order_comment)
from
orders o
left join customer c on c.id=o.customer_id
where o.id=1 and
convert(varchar(255),order_comment) not in
(select b.customer_name from customer b where o.customer_id=b.id)
If the customer_name is already part of the order_comment then the update should not happen.
The above query works ok when the order_comment is empty. But if there is already text in the comment, it keeps updating the value. How should i change the query so when there is already text in the comment section, the update to happen only once?
There a lot of ways to achieve your goal and of course the best way depends on your setup and your further goals.
In order to keep your update statement as most similar as possible to your attempt, you could do this:
UPDATE o SET order_comment=CONCAT(c.customer_name,';',o.order_comment)
FROM
orders o
LEFT JOIN customers c ON c.id=o.customer_id
WHERE o.order_comment IS NULL OR o.order_comment NOT LIKE CONCAT(c.customer_name,'%');
There are also other possibilites like subselects, not exists etc., the best idea is that you try what is the best for you. You can check this example here:
fiddle

In SQL Server, how can I change a column values depending on whether it contains a certain value?

Sorry if the title is a bit confusing... I'm trying to fix some data. Here goes the explanation:
Say I have two tables.
The first is a lookup table that is no longer in use.
The second has one varchar(50) column that sometimes has product names and
sometimes has product ids from the old lookup table.
The idea is to convert all the PID values in the Product table into the product names. Here's a pic i made up to help illustrate it:
The lookup table is much larger, that's just an example. So i'd guess it would be an update statement that would use the ProductsLookup.Name value if the Product value was found to be in the ProductsLookup.PID set? How would this look in SQL?
Thanks much for the help,
Carlos
You need to put inner join with both these tables "ProductsLookup" and "Products" on PID and Product column. But Product column in "Products" table is varchar so you have to apply ISNUMERIC function on this column to make sure that join works fine. below is example
UPDATE
P
SET
P.Product=PL.Name
FROM
Products P
INNER JOIN ProductsLookup PL ON PL.PID=CASE WHEN ISNUMERIC(P.Product)=1 THEN P.Product ELSE -1 END
You can do this with an update and join:
update p
set product = pl.name
from products p join
productslookup pl
on pl.pid = p.id;
A left join is not needed, because you only need to update the values that match in the lookup table.
I will caution you that performance might be an issue. The problem is the types between the two tables -- presumably pid is a number not a string. If so, you can create a computed column to change the type and an index on that column.

how can an unrelated table specified in FROM-clause affect the outcome of SUM()?

I am new to sqlite3 and have made some queries where the outcome seems strange to me. I have two tables, OrderDetails and Offices, that from their schema are unrelated. There are 7 entries in offices and 2996 in OrderDetails. Within OrderDetails, there is a column with quantityOrdered, and by summing the column values I get an accumulated value.
SELECT SUM(quantityOrdered) FROM OrderDetails; (result is 105516)
When I include the other table, which i don't actually extract any information from in my SELECT-clause and should be unrelated in attributes like so:
SELECT SUM(OD.quantityOrdered FROM OrderDetails OD, Offices; (result is 738612)
The result is much higher, and it is interesting to see that it is exactly 7 times larger (the number of entries in offices). I also get it even though I specify that it should only be OrderDetails attributes (OD.quantityOrdered). Is there some obvious logic that I don't see and understand? I hope someone can help me.
You are getting the sum for a CROSS JOIN since you dont have a JOIN condition.
Every row FROM the first table is JOINed to every other row from the other table.
Look here for a basic JOIN tutorial.
It should be
SELECT SUM(OD.quantityOrdered)
FROM OrderDetails OD JOIN Offices O
ON OD.somecol=O.someothercol
When you list two tables in a FROM clause but specify no conditions to relate them together, you get what is known as a CROSS JOIN, which calculates every possible combination of rows from the two tables.
You can see this by running
SELECT *
FROM OrderDetails, Offices
In more modern SQL that would be written
SELECT *
FROM OrderDetails
CROSS JOIN Offices
The SUM() function (without a GROUP BY) runs across all the rows in the result set, regardless of how the resultset was calculated (you can think of the SELECT clause running after the CROSS JOIN).
So your second query takes all the rows created by the CROSS JOIN and sums them up, meaning all the values are counted 7 times.
SELECT SUM(OD.quantityOrdered)
FROM OrderDetails as OD
CROSS JOIN Offices as O

Translate SQL query to absolute beginner (me)

I am trying to understand the JOIN command from w3schools tutorial and there is an example.
Can you please "translate" it to me what exactly it does? I already know what do the dots do, but INNER JOIN, ON and so on messed me up?
SELECT Orders.OrderID, Customers.CustomerName, Orders.OrderDate
FROM Orders
INNER JOIN Customers
ON Orders.CustomerID=Customers.CustomerID;
And does it creates a new table in my SQL database or it just creates (lets call it..) "virtual" table which I can use it in the moment
The dot notation here signifies the column of a table.
Table.Column
So the SELECT is retrieving the columns specified from each table.
JOIN matches the tables based on the condition that appears after ON
this queries joins customers to orders based the condition of having the same CustomerID.
For more on joins check out http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html
Perhaps the first thing to understand is the "dot notation." When you see a value like Orders.CustomerID SQL will read that to mean the CustomerID column within the Orders table.
The INNER JOIN is looking for an exact match for the records you specify with the ON clause...
So, in this example, SQL will first find all the records in the Orders table which have a CustomerID that matches the CustomerID found in the Customers table.
Then, it will look to the SELECT clause and show you the OrderID (from the Orders table), the CustomerName (from the Customers table) and the OrderDate from the Orders table.
If you're using SQL Server Management Studio (SSMS) or some other similar tool, it should display your results - kindof like a virtual table... but it doesn't actually create a table.
Hope that helps,
Russell
There are INNER AND OUTER JOINS. I think this post sums up those differences well.
What is the difference between "INNER JOIN" and "OUTER JOIN"?
As far as the concept itself you are 'joining' the tables by finding things in common between them based on a shared value in each. If you have ever done a vlookup with Microsoft Excel then you are familiar with this concept. In the query you've posted you are selecting values from both the Orders and Customers table. You can tell which table you are selecting values from by the prefix Orders. or Customers. You can then tell which column by the value following the dot i.e. OrderID, CustomerName, OrderDate.
The way the query knows to pull a conjoined field is if the CustomerID field matches.
So step by step
You are selecting
SELECT Orders.OrderID, Customers.CustomerName, Orders.OrderDate
From the table Orders
FROM Orders
You wish to pull corresponding values from Customers. There are numerous join methods and logic that goes with each but you have chosen INNER JOIN explained in the link above.
INNER JOIN Customers
The criteria for joining is CustomerID
ON Orders.CustomerID=Customers.CustomerID;
To use an approximate Excel Vlookup analogy
The Lookup_value is CustomerID
The Table array is ORDERS
The range lookup is the type of join you are performing
SELECT statement returns data, it doesn't create any table not even virtual table whatsoever (if you see any table after executing SELECT statement, thats just a way the returned data presented). Create and modify table done using DDL (Data Definition Language) statements when SELECT is one of DML (Data Manipulation Language) [reference].
Join statement explained very well here, from basic use to more advance with illustration.

Update some table when changes are made in a specific table

This is the database diagram of my sample database:
I want to UPDATE Ingredient Table when changes are made into OrderDetails table with the help of Table Trigger
But the problem is that the Ingredients table may have one or more entries for an Item. I want to update all entries in Ingredient table which are associated with an Item. For more description, see the algorithm below:
For each Ingredient in Ingredients for the current Item:
Update the Quantity in Ingredient table using the formula:
formula: Ingredient.Quantity = Ingredient.Quantity - (Item.Quantity * Ingredients.Quantity)
(The whole idea is whenever Item(s) for an OrderID is Added/Updated/Deleted, the Ingredient(s) Quantity should be decreased/increased by the Quantity mentioned)
We don't iterate or loop in SQL (unless we can avoid it). We describe what we want to happen, and let SQL work out how.
We also, generally, don't store data that we can compute. We can always compute the amount of each ingredient that has been ordered. (If there's another table tracking deliveries from our suppliers, that could also be computed over). If performance was an issue, we'd then consider creating an indexed view - which does include the calculated values, but SQL Server takes care of maintaining it automatically.
In that way, you avoid any discrepancies from creeping in (e.g. if your trigger is disabled).
All that being said, I think the trigger you want is:
create trigger T_OrderDetails
on OrderDetails
after insert,update,delete
as
begin
update ing
set Quantity = ing.Quantity - ((COALESCE(iod.Quantity,0) - COALESCE(dod.Quantity,0)) * i.Quantity)
from
inserted iod
full outer join
deleted dod
on
iod.ItemID = dod.ItemID
inner join
Ingredients i
on
i.ItemID = iod.ItemID or
i.ItemID = dod.ItemID --Cope with OUTER join above
inner join
Ingredient ing
on
i.IngID = ing.IngID
end