Compare differences in 2 tables - mysql

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;

Related

How would you compare 3 tables to 1 in MySQL?

so I have a possibly silly question, but I'm looking for a basic approach or strategy for the following problem.
I have 1 master file and 3 source files, lets call them master, src1, src2, and src3. The master file is SUPPOSED to have the same records as the 3 source files combined, however, the master file has more records than the sum of all 3 sources. My goal is to validate that all records in said src1-3 are inside the master file AND also extract the records from the master that aren't in any 1 of the 3 sources. Additionally, each of the 4 files have different (but similar) headers
I have been able to find the distinct records from src1 (and subsequent sources) and mapped it to the matching records in the master file by using the following :
WITH tmp1 AS (
SELECT src1.*
FROM src1 as s1
LEFT JOIN master as mstr
ON (
s1.name = mstr.fname
s1.quant = mstr.qty
s1.item = mstr.obj
s1.price = mstr.prc
s1.age = mstr.time_since_dob
)
) SELECT DISTINCT primaryKey from tmp1;
Using this, I can get a count of distinct matches between the two files that are present in src1 and if that matches the count from select distinct PK from src1 then I'm in decent shape. Albeit, I know that using the criteria above I could easily get many collision since several records could have the same name, quantity, item, price, etc... But suffice it to say, using the above criteria I can get unique matches since there are no matching ID's between the two tables or anything like that. Additionally, the join criteria for each source is slightly different so I had to do the above 3 separate times and validate each source independently.
Having done the above along with some other analysis, I have been able to validate that each distinct record from src1-3 has at least 1 distinct match in the master file. I'm having issue, however, with the second half of this challenge where I have to select the records from the master file that did NOT have a corresponding match.
How can I select those records from the master file that were not matched? Can I do a simple
select * from master not in newView1 where newView1 is the combination of the 3 selects for the 3 sources? Again, I'm using different columns for each join condition so putting 3 sources under the same header might be difficult (but worth pursuing?). Another thing worth mentioning is that each file is ~1gb and the master file is ~3gb so time complexity is worth considering.
Thanks for all and any help.
First, using UNION ALL to get all matching rows and rows contained only in src1-3 tables.
Next, getting also rows of the master table that is contained only in the master table by joining with the tmp1 table.
Refer to the following query:
with tmp1(tbl,name,quant,item,price,age,fname,qty,obj,prc,time_since_dob) as (
select 'src1',s1.*,m.* from src1 s1 left join master1 m on
s1.name=m.fname and
s1.quant=m.qty and
s1.item=m.obj and
s1.price=m.prc and
s1.age=m.time_since_dob
union all
select 'src2',s2.*,m.* from src2 s2 left join master1 m on
s2.name=m.fname and
s2.quant=m.qty and
s2.item=m.obj and
s2.price=m.prc and
s2.age=m.time_since_dob
union all
select 'src3',s3.*,m.* from src3 s3 left join master1 m on
s3.name=m.fname and
s3.quant=m.qty and
s3.item=m.obj and
s3.price=m.prc and
s3.age=m.time_since_dob
)
select 'master',m.fname,m.qty,m.obj,m.prc,m.time_since_dob from master1 m left join tmp1 t on
m.fname=t.name and
m.qty=t.quant and
m.obj=t.item and
m.prc=t.price and
m.time_since_dob=t.age
where t.name is null
union all
select t.tbl,t.name,t.quant,t.item,t.price,t.age from tmp1 t
where t.fname is null
db fiddle

Trigger minusing from one table to another table 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;

How to use one table multiple times for inner join in SQL Server?

I am trying to make a table that includes join between 3 tables in the MSSS 2008. There is a fact table, a date table, and a course table. I should join them to make a base table. In date table there is a one parameter that name is Academic Year lookup, and the values in this parameter is like 2000/1, 2001/2. This parameter in the base table should separate to three parameter such as CensusYear, StartYear, and ApplicationYear. Therefore, I need the data table multiple times. I executed a inner join query, and already I have four inner join statement, but I am getting some extra years, and I'm losing some years. I believe, my query should be wrong somewhere.
The attached file is include the design view that created in the MS Access, it'll help to see the tables, and understand what I need to create.
[Design View in Ms Access][1]
SELECT
A.[EventCount],
B.[AcademicYearLookup] AS [CensusYear],
C.[AcademicYearLookup] AS [StartYear],
D.[AcademicYearLookup] AS [ApplicationYear],
B.[CurrentWeekComparisonFlag],
B.[AcademicWeekOfYear],
case
when A.[ApplicationCensusSK] = 1 then 'Same Year'
when A.[ApplicationCensusSK] = 2 then 'Next Year'
when A.[ApplicationCensusSK] = 5 then 'Last Year'
ELSE 'Other'
END as [CensusYearDescription],
B.[CurrentAcademicYear],
A.[StudentCodeBK],
A.[ApplicationSequenceNoBK],
A.[CourseSK],
A.[CourseGroupSK],
A.[CourseMoaSK],
A.[CboSK],
A.[CourseTaughtAbroadSK],
A.[ApplicationStatusSK],
A.[ApplicationFeeStatusSK],
A.[DecisionResponseSK],
A.[NationalityCountrySK],
A.[DomicileCountrySK],
A.[TargetRegionSK],
A.[InternationalSponsorSK] INTO dbo.[BaseTable3yrs]
FROM Student.FactApplicationSnapshot A
INNER JOIN Conformed.DimDate AS B ON A.[CensusDateSK] = B.[DateSK]
INNER JOIN Conformed.DimDate AS C ON A.[AcademicYearStartDateSK] = C.[DateSK]
INNER JOIN Conformed.DimDate AS D ON A.[ApplicationDateSK] = D.[DateSK]
INNER JOIN Student.DimCourse ON A.CourseSK = Student.DimCourse.CourseSK
WHERE (((B.CurrentAcademicYear) In (0,-1))
AND ((A.ApplicationCensusSK) In (1,2,5))
AND ((Student.DimCourse.DepartmentShortName)= 'TEACH ED'));
/* the query to check that the result it's correct or not, and I check it by academic week of year, and I found that I am lossing some data, and I have some extra data, means maybe join is wrong*/
select * from [BaseTable3yrs]
where [StudentCodeBK]= '26002423'
AND [ApplicationSequenceNoBK] = '0101'
order by [AcademicWeekOfYear]
When doing recursive joins like this, it's easy to get duplicate records. You could try gathering the Conformed data separately into a table variable and then joining to it. This would also make your query more readable.
You might also try a SELECT DISTINCT on your main query.

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...

Compare Table with a monitoring point - mysql

i have a table that contains product data with prices. The table updated every 5 - 10 minutes.
Now i have a cronjob that makes a monitoring point by copying the table.
So i get a copy of the data every morning.
Now i want to check my prices at the evening by comparing them with the monitor table.
How could my query look like to get the two prices.
The query should show products where the prices are different.
Table a
[id] - [product_no] [product_desc] [product_price] - [product_stock]
Table b (from cronjob]
[id] - [product_no] [product_desc] [product_price] - [product_stock]
You ask for a basic join between two tables. Here is how a join can be performed:
SELECT TableA.product_no
, TableA.product_price AS TableAPrice
, TableB.product_price AS TableBPrice
FROM TableA
INNER JOIN TableB
ON TableA.id = TableB.id
WHERE TableA.product_price != TableB.product_price
Try to learn how joins are working in general, this is a very important thing to know when working with databases.