Update some table when changes are made in a specific table - sql

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

Related

UPDATE statement won't update anything

I've been creating a recipe database for a class project using SSMS. I have one table with all the recipe names that I'd inserted into a lookup table (RecipeDetails), but I'd left out their associated IDs, so I wanted to write a bit of code to update my table with those values. I feel like this code should work fine (it seemed to work in the past, but I screwed up something unrelated and had to restore my most recent database backup), but now it just isn't. It says it's affected all the rows I expect it to affect, but those rows still list the RecipeID as NULL.
I'm pulling my data from RecipesTable, which includes the names of each recipe and an ID for each. In RecipeDetails I have a column for RecipeName, RecipeID, Ingredient, IngredientID, and an ID for each row in the table. As of now, I have all my recipes in the table, but not their associated ID. I would like to move the ID's over from one table to another.
UPDATE rd
SET rd.RecipeID = rt.RecipeID
FROM RecipeDetail AS rd
FULL JOIN RecipesTable AS rt ON rd.RecipeID = rt.RecipeID
WHERE rt.RecipeName = rd.RecipeName;
You should use an inner join rather than an outer join.
UPDATE rd
SET rd.RecipeID = rt.RecipeID
FROM RecipeDetail rd JOIN
RecipesTable rt
ON rd.RecipeName = rt.RecipeName;

Join 2 tables based on column name present in a table row

I have a table called Target where I have 5 columns:
ProductLevel
ProductName
CustomerLevel
CustomerName
Target
In another table called Products I have 3 columns:
ProductId
ProductCategory
ProductBrand
In the 3rd table called Customer I have 3 columns:
CustomerID
CustomerName
SubCustomerName
Is there a way to do a dynamic join where I select the column I will use in the JOIN based on the value that I have in the 1st table?
Example: If in the first table I have Category in ProductLevel, I'll join the table product using ProductCategory field. If I have Brand, I'll join using ProductBrand... The same happens with Customer table.
PS: I'm looking for a way to create it dynamically in a way I can add new columns to that tables without changing my code, then in the future I can have ProductSegment column in Product Table and Segment as a value in ProductLevel in Target table.
Yes, like this:
SELECT * FROM
Target t
INNER JOIN
Product p
ON
(t.ProductLevel = 'Category' AND t.??? = p.ProductCategory)
OR
(t.ProductLevel = 'Brand' AND t.??? = p.ProductBrand)
You didn't say which column in Target holds your product category/brand hence the ??? in the query above. Replace ??? with something sensible
PS; you can't do as you ask in your PS, and even this structure above is an indicator that your data model is broken. You can at least put the code in for it now even if there are no rows with t.ProductLevel = 'Segment'
Don't expect this to perform well or scale.. You might be able to improve performance by doing it as a set of UNION queries rather than OR, but you may run into issues where indexes aren't used, crippling performance

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.

soft delete or hard delete good for eCommerce

I have already read this post but I am concerned the best solution for eCommerce site
Our scenario:
Product table
ProductID Name Price
OrderDetails table
OrderID ProductID
OrderDetails table has FK ProductID referrenced to ProductID of Product table
once product has been deleted, how are you going to display the historical order report?
Options:
soft delete disadvantage - it affects db storage performance
hard delete disadvantage - need extra join query while taking report
Any help would be great.
I would definitely go with soft delete. Especially if in an e-commerce context.
How about storing deleted products in an ArchivedProduct table and then doing the following:
SELECT
*
FROM
OrderDetails RIGHT JOIN Product ON OrderDetails.ProductID = Product.ProductID
UNION ALL
SELECT
*
FROM
OrderDetails RIGHT JOIN ArchivedProduct ON OrderDetails.ProductID = ArchivedProduct.ProductID
When you say
it affects db storage performance
Yes, there is an overhead in terms of performance which is entirely dependent upon the size of the 3 tables.
If at a later stage you wanted to increase the performance of the query, you could either wipe out some of the previously "deleted" products from the ArchivedProduct table based on your own considerations (for example, all products inserted prior to ...) or add some constraints to the second SELECT statement. You'd still be in a safer position than with a hard delete.

Multi update query

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