Trigger minusing from one table to another table MYSQL - mysql

So, i have two table at the minute...
Freezing - (id, et1, straw, eps) &
Inventory - (id, et1, owner, total)
I need it so that when someone enters something into Freezing, and whatever is entered into 'EPS' in freezing will take off 'total' in Inventory. The common column between these 2 tables is the et1 number. Currently the statement I'm using below enters, however it does not affect the total in Inventory. If someone could help me see where i'm going wrong that would be brilliant.
UPDATE et1209_inventory
SET total = total - "et1202_freezing.EPS"
WHERE "et1202_freezing.EPS" = total

If I understand you correctly it would probably be the easiest to just create a third table that joins Freezing and Inventory:
create table if not exists Output_table as
select i.id, i.et1, i.owner, f.eps - i.total
from Freezing f
join Inventory i on f.id = i.id;

Related

Compare differences in 2 tables

I am running a MySQL Server on Ubuntu, patched up to date...
In MySQL, I have 2 tables in a database. I am trying to get a stock query change working and it kind of is, but it's not :(
What I have is a table (table A) that holds the last time I have checked stock levels, and another table (table B) that holds current stock levels. Each table has identical column names and types.
What I want to do is report on the changes from table B. The reason is that there are about 1/2 million items in this table - and I cannot just update each item using the table as a source as I am limited to 100 changes at a time. So, ideally, I want to get the changes - store them in a temporary table, and use that table to update our system with just those changes...
The following below brings back the changes but shows both Table A and Table B.
I have tried using a Left Join to only report back on Table B but I'm not a mysql (or any SQL) guy, and googling all this... Can anyone help please. TIA. Stuart
SELECT StockItemName,StockLevel
FROM (
SELECT StockItemName,StockLevel FROM stock
UNION ALL
SELECT StockItemName,StockLevel FROM stock_copy
) tbl
GROUP BY StockItemName,StockLevel
HAVING count(*) = 1
ORDER BY StockItemName;
The query below spit out records that have different stock level in both table.
SELECT s.StockItemName, s.StockLevel, sc.StockLevel
FROM stock s
LEFT JOIN stock_copy sc ON sc.Id = s.Id AND sc.StockLevel <> s.StockLevel
ORDER BY s.StockItemName
ok - I solved it - as there wasn't a unique ID on each table that could be matched, and rather than make one, I used 3 colums to create the unique ID and left joined on that.
SELECT sc.StockItem, sc.StockItemName, sc.Warehouse, sc.stocklevel
FROM stock s
LEFT JOIN stock_copy sc ON (sc.StockItem = s.StockItem AND sc.StockItemName = s.StockItemName AND sc.Warehouse = s.Warehouse AND sc.StockLevel <> s.StockLevel)
having sc.StockLevel is not Null;

Creating joins based on range of number value

Could you guys provide me on the situation below?
I have 2 tables.
Table 1 looks like this:
Meanwhile, this is table 2:
I would like to join table 2 to table 1 to lookup the grade for each job based on the upper and lower limit column.
By conceptualizing some of the lovely answers here, I manage to come up with a statement that looks something like this:
FROM table2 LEFT JOIN table1 ON (table2.[score] >= table1.[lower limit]) AND (table2.[score] <= table1.[upper limit])
The statement above manage to join them according to a range, however, for some unknown reasons, some rows from the left table went missing and I could not determine what it is. e.g (2000 rows in table 2, but only 1800 in the query)
I am sure the join is the cause, as if i change the join to a equal left join, 2000 rows appear in the query.
Can someone advice me on this?
Regards,
Guang Yong
Perhaps it would be much cleaner to create a table with values from 1-100 and assign them each on of your categories, and essentially mirroring your table 1.
Then you can do Table 2
SELECT Table1.Grade, Table2.Score
FROM Table2 LEFT JOIN Table1 ON Table2.Score = Table1.Score
This would definitely cover all integers between 0 and 100.
If you are manually inputing the scores, you could also use a data macro as simple as this:
go to Table Tools >> Table >> Before Change
Then use the Set Field Action, and set
Name = Table2.Grade
Value = IIf([Score]>=70,"Good",IIf([Score]<=59,"bad","so so"))
With this ^ everytime you type in a score, it will automatically populate the grade column.
Another option is create a query as follows, that will evaluate each line and assign the proper grade:
SELECT Table2.Score,
IIf([Score]>=70,"Good",IIf([Score]<=59,"bad","so so")) AS Grade
FROM Table2;
Good luck!

How to store SQL Query result in table column

I'm aware of the INSERT INTO table_name QUERY; however, I'm unsure how to go about achieving the desired result in this case.
Here's a slightly contrived example to explain what I'm looking for, but I'm afraid I cannot put it more succiently.
I have two tables in a database designed for a hotel.
BOOKING and CUSTOMER_BOOKING
Where BOOKING contains PK_room_number, room_type, etc. and CUSTOMER_BOOKING contains FK_room_number, FK_cusomer_id
CUSTOMER_BOOKING is a linking table (many customers can make many bookings, and many bookings can consist of many customers).
Ultimately, in the application back-end I want to be able to list all rooms that have less than 3 customers associated with them. I could execute this a separate query and save the result in the server-side scripting.
However, a more elegant solution (from my point of view) is to store this within the BOOKING table itself. That is to add a column no_of_bookings that counts the number of times the current PK_room_number appears as the foreign key FK_room_number within the CUSTOMER_BOOKING table. And why do this instead? Because it would be impossible for me to write a single complicated query which will both include the information from all ROOMS, among other tables, and also count the occurrences of bookings, without excluding ROOMS that don't have any bookings. A very bad thing for a hotel website attempting to show free rooms!
So it would look like this
BOOKING: PK_room_number (104B) room_type (double) room_price (high), no_of_bookings (3)
BOOKING: PK_room_number (108C) room_type (single) room_price (low), no_of_bookings (1)
CUSTOMER_BOOKING: FK_room_number (104B) FK_customer_id (4312)
CUSTOMER_BOOKING: FK_room_number (104B) FK_customer_id (6372)
CUSTOMER_BOOKING: FK_room_number (104B) FK_customer_id (1112)
CUSTOMER_BOOKING: FK_room_number (108C) FK_customer_id (9181)
How would I go about creating this?
Because it would be impossible for me to write a single complicated
query which will both include the information from all ROOMS, among
other tables, and also count the occurrences of bookings, without
excluding ROOMS that don't have any bookings.
I wouldn't say it's impossible and unless you're running into performance issues, it's easier to implement than adding a new summary column:
select b.*, count(cb.room_number)
from bookings b
left join customer_booking cb on b.room_number = cb.room_number
group by b.room_number
Depending on your query may need to use a derived table containing the booking counts for each room instead instead
select b.*, coalesce(t1.number_of_bookings,0) number_of_bookings
from bookings b
left join (
select room_number, count(*) number_of_bookings
from customer_booking
group by room_number
) t1 on t1.room_number = b.room_number
You have to left join the derived table and select coalesce(t1.number_of_bookings,0) in case a room does not have any entries in the derived table (i.e. 0 bookings).
A summary column is a good idea when you're running into performance issues with counting the # of bookings each time. In that case I recommend creating insert and delete triggers on the customer_booking table that either increment or decrement the number_of_bookings column.
You could do it in a single straight select like this:
select DISTINCT
b1.room_pk,
c1.no_of_bookings
from cust_bookings b1,
(select room_pk, count(1) as no_of_bookings
from cust_bookings
group by room_pk) c1
where b1.room_pk = c1.room_pk
having c1.no_of_bookings < 3
Sorry i used my own table names to test it but you should figure it out easily enough. Also, the "having" line is only there to limit the rows returned to rooms with less than 3 bookings. If you remove that line you will get everything and could use the same sql to update a column on the bookings table if you still want to go that route.
Consider below solutions.
A simple aggregate query to count the customers per each booking:
SELECT b.PK_room_number, Count(c.FK_customer_id)
FROM Booking b
INNER JOIN Customer_Booking c ON b.PK_room_number = c.FK_room_number
GROUP BY b.PK_room_number
HAVING Count(c.FK_customer_id) < 3; # ADD 3 ROOM MAX FILTER
And if you intend to use a new column no_of_booking, here is an update query (using aggregate subquery) to run right after inserting new value from web frontend:
UPDATE Booking b
INNER JOIN
(SELECT b.PK_room_number, Count(c.FK_customer_id) As customercount
FROM Booking b
INNER JOIN Customer_Booking c ON b.PK_room_number = c.FK_room_number
GROUP BY b.PK_room_number) As r
ON b.PK_room_number = r.PK_room_number
SET b.no_of_booking = r.customercount;
the following generates a list showing all of the bookings and a flag of 0 or 1 if the the room has a customer for each of the rooms. it will display some rooms multiple times if there are multiple customers.
select BOOKING.*,
case CUSTOMER_BOOKING.FK_ROOM_NUMBER is null THEN 0 ELSE 1 END AS BOOKING_FLAG
from BOOKING LEFT OUTER JOIN CUSTOMER_BOOKING
ON BOOKING.PK_room_numer = CUSTOMER_BOOKING.FK_room_number
summing and grouping we arrive at:
select BOOKING.*,
SUM(case when CUSTOMER_BOOKING.FK_ROOM_NUMBER is null THEN 0 ELSE 1 END) AS BOOKING_COUNT
from BOOKING LEFT OUTER JOIN CUSTOMER_BOOKING
ON BOOKING.PK_room_number = CUSTOMER_BOOKING.FK_room_number
GROUP BY BOOKING.PK_room_number
there are at least two other solutions I can think of off the top of my head...

Invalid results returning from a multi-table SELECT Statement

I have a Database with the following structure:
http://i.imgur.com/DFZz3Py.png
I'm trying to run a select statement, getting information from multiple tables, however it keeps bringing me duplicate results. The statement I'm using is:
SELECT StockReceipts.StockID, StockReceipts.Quantity, StockPriceHistory.Price
FROM StockReceipts,StockPriceHistory,Receipts
WHERE (Receipts.ReceiptID = 1) AND (Receipts.OrderDate BETWEEN StockPriceHistory.DateStart AND StockPriceHistory.DateEnd)
And the results i'm getting are:
http://i.imgur.com/2ZrgYyZ.png
What I actually want is matching rows from the stockreceipts table,
but with the price for each item of stock (the price that was within the date & time of ordering - OrderDate taken from the Receipts table) as well, taken from the StockPriceHistory table. I don't understand why it's making up duplicate/incorrect rows when there are only two rows in the StockReceipts table for that receipt.
Can anyone help? Thanks
SELECT
SR.StockID,
SR.Quantity,
SPH.Price
FROM
Receipts R
JOIN StockReceipts SR
on R.ReceiptID = SR.ReceiptID
JOIN StockPriceHistory SPH
on SR.StockID = SPH.StockID
WHERE
R.ReceiptID = 1
AND R.OrderDate BETWEEN SPH.DateStart AND SPH.DateEnd
You had no JOIN conditions between the tables leaving it a Cartesian result... For every record in one, grabbed entries from all other table rows.

How do I get MYSQL to join a whole table?

I have a SELECT query that returns the response based on an unique ID, so I always get just one row.
I thought that I could save my machine an extra SELECT query if I simply added the prices table to the result, and read them to memory later on.
Would that be a good approach or am I missing something ?
(I tried it out and seems to get the job done)
SELECT *
FROM subscriptions
LEFT JOIN prices ON 1=1
WHERE subscriptions.ID = 100
edit: The prices table has no ID. I just need to get the complete table, I used to have a different SELECT just for that
This looks like a terrible idea... you should join the subscriptions table to the prices table using the foreign key that you (supposedly/should) have.
Assuming your prices table has a subscription ID column then your query should look something like this:
SELECT *
FROM subscriptions LEFT JOIN prices ON subscriptions.ID=prices.ID
WHERE subscriptions.ID=100
What this will do is produce a cartesian join - not too bad since you're limiting the 'subscriptions' side of things to a single record, but will still produce as many rows as there's records in the price side. Where this gets bad is when you've got multiple rows on both sides. Then you get n x m results - think of how big the result set would be if you had 50,000 subscriptions joined against 1000 prices: 50,000 x 1,000 = 50 million result rows.
First off, this approach is going to be much less clear what you're doing than two SELECT statements unless there is an actual relation between the tables. Second, it's probably going to be slower, because you're transferring much more data (each row of prices additionally gets all the fields from subscriptions copied).
If subscriptions and prices are related, you want to change that ON condition to use the relation, so you're only pulling the data you need.
SELECT *
FROM subscriptions s LEFT JOIN prices p ON (s.subscription_id = p.subscription_id)
WHERE s.subscription_id = 100
One thing you definitely don't want to do is this:
SELECT *
FROM subscriptions s LEFT JOIN prices p ON (1=1)
as that'd pull the full Cartesian product. Once your tables get sufficiently large, that will run you out of temporary table space.
why your condition have 1=1 ?
I thing that is's must something like this:
SELECT s.*,p.*
FROM subscriptions as s
LEFT JOIN prices as p ON p.product_id=s.product_id
WHERE s.ID = 100
show me your full fields of tables subscriptions and prices to help for you
This?
SELECT *
FROM subscriptions, prices
WHERE subscriptions.ID = 100
You'll get horrible results like this, but it seems this is what you wanted.
The table with less rows will have its rows repeating. Again, this is not a good practice.
Use two SELECTs.
This is a cross join http://en.wikipedia.org/wiki/Join_(SQL)#Cross_join
which means your resultset will contain as many rows as you have in the prices table.
So I guess it is not a good idea