Trigger that updates stock levels after a sale - mysql-workbench

I am trying to create a trigger that will automatically update my stock levels after a sale has taken place i.e. after I input a new entry in my sales table.
Relevant tables and columns:
Product.Quantity_held (Represents Stock)
Sales.Quantity (Represents sales)
The below is where I am so far and this successfully creates the trigger, however when I insert details for a new sale, the Product.Quantity_held figure does not update.
Any ideas why please?
DELIMITER //
create trigger StockUpdate
after update on sales
for each row begin
insert into Product
set action = 'update',
Quantity_held = (Quantity_held - New.Quantity);
END;

I guess you need below by just swapping your INSERT and UPDATE keywords -
DELIMITER //
create trigger StockUpdate
after insert on sales
for each row begin
update Product
set action = 'update',
Quantity_held = (Quantity_held - New.Quantity);
END;

You need to update the table and filter for the correct product:
create trigger StockUpdate after update on sales
for each row
begin
update Product
set action = 'update',
Quantity_held = (Quantity_held - New.Quantity)
where product_id = new.product_id
end;
You probably need insert and delete triggers as well if this has any hope of being accurate.

Related

How to use dynamic regex to match value in Postgres

SUMMARY: I've two tables I want to derive info out of: family_values (family_name, item_regex) and product_ids (product_id) to be able to update the property family_name in a third.
Here the plan is to grab a json array from the small family_values table and use the column value item_regex to do a test match against the product_id for every row in product_ids.
MORE DETAILS: Importing static data from CSV to table of orders. But, in evaluating cost of goods and market value I'm needing to continuously determine family from a prefix regex (item_regex from family_values) match on the product_id.
On the client this looks like this:
const families = {
FOOBAR: 'Big Ogre',
FOOBA: 'Wood Elf',
FOO: 'Valkyrie'
};
// And to find family, and subsequently COGs and Market Value:
const findFamily = product_id => Object.keys(families).find(f => new RegExp('^' + f).test(product_id));
This is a huge hit for the client so I made a family_values table in PG to include a representative: family_name, item_regex, cogs, market_value.
Then, the product_ids has a list of only the products the app cares about (out of millions). This is actually used with an insert trigger 'on before' to ignore any CSV entries that aren't in the product_ids view. So, I guess after that the product_ids view could be taken out of the equation because the orders, after inserting readonly data, has its own matching product_id. It does NOT have family_name, so I still have the issue of determining that client-side.
PSUEDO CODE: update family column of orders with family_name from family_values regex match against orders.product_id
OR update the product_ids table with a new family column and use that with the existing on insert trigger (used to left pad zeros and normalize data right now). Now I'm thinking this may be just an update as suggested, but not real good with regex in PG. I'm a PG novice.
PROBLEM: But, I'm having a hangup in doing what I thought would be like a JS Array Find operation. The family_values have been sorted on the item_regex so that the most strict match would be on top, and therefor found first.
For example, with sorting we have:
family_values_array = [
{"family_name": "Big Ogre", "item_regex": "FOOBAR"},
{"family_name": "Wood Elf", "item_regex": "FOOBA"},
{"family_name": "Valkyrie", "item_regex": "FOO"}]
So, that the comparison of product_id of ^FOOBA would yield family "Wood Elf".
SOLUTION:
The solution I finally came about using was simply using concat to write out the front-anchored regex. It was so simple in the end. The key line I was missing is:
select * into family_value_row from iol.family_values
where lvl3_id = product_row.lvl3_id and product_row.product_id
like concat(item_regex, '%') limit 1;
Whole function:
create or replace function iol.populate_families () returns void as $$
declare
product_row record;
family_value_row record;
begin
for product_row in
select product_id, lvl3_id from iol.products
loop
-- family_name is what we want after finding the BEST match fr a product_id against item_regex
select * into family_value_row from iol.family_values
where lvl3_id = product_row.lvl3_id and product_row.product_id like concat(item_regex, '%') limit 1;
-- update family_name and value columns
update iol.products set
family_name = family_value_row.family_name,
cog_cents = family_value_row.cog_cents,
market_value_cents = family_value_row.market_value_cents
where product_id = product_row.product_id;
end loop;
end;
$$
LANGUAGE plpgsql;
Use concat as updated above:
select * into family_value_row from iol.family_values
where lvl3_id = product_row.lvl3_id and product_row.product_id
like concat(item_regex, '%') limit 1;

Return Record as text

I have the following on a postgres function:
ret_feedback RECORD;
t_query_feedback =
'SELECT
company,
country,
vendor,
FROM
mytable
limit 100
execute t_query_feedback into ret_feedback;
return ret_feedback.company;
It works for "company" but it just returns the first row, how can I return them all?
Also, what's the best way to return the whole table from the query above? At a later stage I would need to send an email with the contents of this table.
Thanks,

Postgresql - Rule with On Conflict Statement

I have a table in postgres with columns link(PK), person, places and date. I would like to create a rule that when insert is command is issued from my backend program then if there is a conflict on the link column it would do an upsert ( update the person, places and date) columns for the same link. I cannot figure out the format of the rule. Below is pseudo code of what I am looking for.
Create Rule rssmodel as on
INSERT into public.rssmodel
On conflict (link)
do UPDATE public.rssmodel
set person = data, places=data, date=data
You could do something like this to achieve that:
CREATE RULE rssmodel_insert AS ON
INSERT TO public.rssmodel
WHERE EXISTS (SELECT 1 from rssmodel where NEW.link = link)
DO INSTEAD
UPDATE public.rssmodel
SET person = NEW.person, places = NEW.places, date = NEW.date WHERE link = NEW.link;

updatexml for particular rows only

Context: I want to increase the allowance value of some employees from £1875 to £7500, and update their balance to be £7500 minus whatever they have currently used.
My Update statement works for one employee at a time, but I need to update around 200 records, out of a table containing about 6000.
I am struggling to workout how to modify the below to update more than one record, but only the 200 records I need to update.
UPDATE employeeaccounts
SET xml = To_clob(Updatexml(Xmltype(xml),
'/EmployeeAccount/CurrentAllowance/text()',187500,
'/EmployeeAccount/AllowanceBalance/text()',
750000 - (SELECT Extractvalue(Xmltype(xml),
'/EmployeeAccount/AllowanceBalance',
'xmlns:ts=\"http://schemas.com/\", xmlns:xt=\"http://schemas.com\"'
)
FROM employeeaccounts
WHERE id = '123456')))
WHERE id = '123456'
Example of xml column (stored as clob) that I want to update. Table has column ID that hold PK of employees ID EG 123456
<EmployeeAccount>
<LastUpdated>2016-06-03T09:26:38+01:00</LastUpdated>
<MajorVersion>1</MajorVersion>
<MinorVersion>2</MinorVersion>
<EmployeeID>123456</EmployeeID>
<CurrencyID>GBP</CurrencyID>
<CurrentAllowance>187500</CurrentAllowance>
<AllowanceBalance>100000</AllowanceBalance>
<EarnedDiscount>0.0</EarnedDiscount>
<NormalDiscount>0.0</NormalDiscount>
<AccountCreditLimit>0</AccountCreditLimit>
<AccountBalance>0</AccountBalance>
</EmployeeAccount>
You don't need a subquery to get the old balance, you can use the value from the current row; which means you don't need to correlate that subquery and can just use an in() in the main statement:
UPDATE employeeaccounts
SET xml = To_clob(Updatexml(Xmltype(xml),
'/EmployeeAccount/CurrentAllowance/text()',187500,
'/EmployeeAccount/AllowanceBalance/text()',
750000 - Extractvalue(Xmltype(xml),
'/EmployeeAccount/AllowanceBalance',
'xmlns:ts=\"http://schemas.com/\", xmlns:xt=\"http://schemas.com\"')
))
WHERE id in (123456, 654321, ...);

t sql select into existing table new column

Hi I have a temp table (#temptable1) and I want to add a column from another temp table (#temptable2) into that, my query is as follows:
select
Customer
,CustName
,KeyAccountGroups
,sum(Weeksales) as Weeksales
into #temptable1
group by Customer
,CustName
,KeyAccountGroups
select
SUM(QtyInvoiced) as MonthTot
,Customer
into #temptalbe2
from SalesSum
where InvoiceDate between #dtMonthStart and #dtMonthEnd
group by Customer
INSERT INTO #temptable1
SELECT MonthTot FROM #temptable2
where #temptable1.Customer = #temptable2.Customer
I get the following: Column name or number of supplied values does not match table definition.
In an INSERT statement you cannot reference the table you are inserting into. An insert works under the assumption that a new row is to be created. That means there is no existing row that could be referenced.
The functionality you are looking for is provided by the UPDATE statement:
UPDATE t1
SET MonthTot = t2.MonthTot
FROM #temptable1 t1
JOIN #temptable2 t2
ON t1.Customer = t2.Customer;
Be aware however, that this logic requires the Customer column in t2 to be unique. If you have duplicate values in that table the query will seem to run fine, however you will end up with randomly changing results.
For more details on how to combine two tables in an UPDATE or DELETE check out my A Join A Day - UPDATE & DELETE post.
If I understand it correctly you want to do two things.
1: Alter table #temptable1 and add a new column.
2: Fill that column with the values of #temptable2
ALTER #temptable1 ADD COLUMN MothTot DATETIME
UPDATE #temptable1 SET MothTot = (
SELECT MonthTot
FROM #temptable2
WHERE #temptable2.Customer = #temptable1.Customer)