MySQL query: Slow response when joining table using ifnull - mysql

I have three tables, products, variants, and data.
Each product has it's own productcode. Products can have any number of variants including none. Variants have their own code variantcode. Products have a productid column, and each variant has a related productid column.
I want a list of all the codes, but I only care about the productcode if a product has no variants. Otherwise I want the variantcode. I wrote this query to get this list:
SELECT IFNULL(variants.variantcode, products.productcode) AS code
FROM products
LEFT OUTER JOIN variants ON (products.productid = variants.productid)
ORDER BY code
This query works as I expected.
The data table contains extra data for each code. I want to join this data onto this list. I tried this query:
SELECT IFNULL(variants.variantcode, products.productcode) AS code
FROM products
LEFT OUTER JOIN variants ON (products.productid = variants.productid)
LEFT OUTER JOIN data ON (data.partno = code)
ORDER BY code
But I get an error "Unknown column 'code' in 'on clause'". I assumed this had something to do with code being a generated value, so I then tried this query:
SELECT IFNULL(variants.variantcode, products.productcode) AS code
FROM products
LEFT OUTER JOIN variants ON (products.productid = variants.productid)
LEFT OUTER JOIN data ON (data.partno = IFNULL(variants.variantcode, products.productcode))
ORDER BY code
This query worked, but took a long time (~20 seconds vs <1 second for the first query). Is the IFNULL in the ON clause the problem? How can I speed it up?

Try this:
select product_variants.code from
(SELECT IFNULL(variants.variantcode, products.productcode) AS code
FROM products
LEFT OUTER JOIN variants ON (products.productid = variants.productid)
ORDER BY code)
as product_variants
LEFT OUTER JOIN data ON (data.partno = product_variants.code)

One thing you can try is to join to your data table twice, something like this:
SELECT IFNULL(variants.variantcode, products.productcode) AS code
, IFNULL(D1.something, D2.something) AS something
FROM products
LEFT OUTER JOIN variants
ON (products.productid = variants.productid)
LEFT OUTER JOIN data as D1
ON (D1.partno = variants.variantcode)
LEFT OUTER JOIN data as D2
ON (D2.partno = products.productcode)
ORDER BY code

Related

Mysql count left join strange result

Can someone help me to understand those results ? (For me all 3 should return 6455).
(Using RDS mysql-8.0.13)
SELECT COUNT(p.product_id) FROM product p LEFT JOIN product_attributes pa ON p.pdt_id = pa.pdt_id WHERE pa.code = 'season';
Results : 6332
SELECT COUNT(*) FROM product p;
Results : 6455
SELECT COUNT(p.product_id) FROM product p LEFT JOIN product_attributes pa ON p.pdt_id = pa.pdt_id AND pa.code = 'season';
Results : 6455
Your first join uses the WHERE clause, this mean sit selected all the rows, including those with a null join and then filters out those WHERE the pa.code = season, i.e. the null joins.
The last one joins on both, but because it is a left join you still get the full table of results, and nothing is filtered because you remove the WHERE clause. If you were to use an INNER JOIN in the last query you should get the same result (6332).
This link might be useful What's the difference between INNER JOIN, LEFT JOIN, RIGHT JOIN and FULL JOIN?

Keeping Records That Are Not Joined MYSQL

I have the following query in my application:
SELECT
p.old_product_id,
l.product_id,
p.sku,
p.title,
p.option_one,
p.option_two,
FROM
lookup_id l
JOIN temp_price_tables_data p USING (sku);
And it works great. However, a small percentage of records from the temp_price_tables_data tables don't make it to the results.
This is because the skus from the lookup_id table don't exist in the temp_price_tables_data.
Is there a way to keep these records in the new data?
Or is there a way to only get those records so I can store the result for later processing?
EDIT:
First table columns = old_product_id, sku, title, option_one, option_two
Second table column = product_id, sku
Tables should have SKU in common.
Use a left outer join:
SELECT
*
FROM
lookup_id l
LEFT OUTER JOIN price_tables_data p on l.sku = p.sku
WHERE old_product_id IS NULL;
That will get you all the records that are in temp_price_tables_data but not in lookup_id

Need to join MySql query to 3 tables

SELECT products.acctnum,products.subacctnum,NOW(),
items.amount,items.id,items.invoice_id,items.product_id,
items.po_id, invoices.customer_id, purchaseorders.vendor_id FROM items
INNER JOIN (products, invoices, purchaseorders)
ON (items.product_id=products.product_id AND items.invoice_id=invoices.id
AND items.po_id=purchaseorders.id)
This returns nothing... however..
SELECT products.acctnum,products.subacctnum,NOW(),
items.amount,items.id,items.invoice_id,items.product_id,
items.po_id, purchaseorders.vendor_id FROM items
INNER JOIN (products, purchaseorders)
ON (products.product_id=items.product_id AND purchaseorders.id=items.po_id)
Works...
SELECT products.acctnum,products.subacctnum,NOW(),
items.amount,items.id,items.invoice_id,items.product_id,
items.po_id, invoices.customer_id FROM items
INNER JOIN (products, invoices)
ON (products.product_id=items.product_id AND invoices.id=items.invoice_id)
Works...
Works for the rows I need in the result but when I join the 3rd table it doesn't work. LEFT JOIN displayed all the columns I needed but some rows were NULL.
I imagine the join clause you want looks more like this:
FROM items LEFT JOIN
invoices
ON invoices.id = items.invoice_id LEFT JOIN
purchaseorders
ON purchaseorders.id = items.po_id LEFT JOIN
products
ON products.product_id = items.product_id
I'm not sure which fields are not valid when you select them, but you can probably fix such issues by using coalesce() with appropriate fields from invoices and purchaseorders.

AVG + Inner join

I'm trying to make something like a chart list and my actual query is like this:
SELECT
user.username,
songs.*,
albums.desc,
albums.release,
albums.name,
AVG(songrating.rating)
FROM
songs
INNER JOIN
user
ON
songs.userid=user.id
INNER JOIN
albums
ON
songs.albumid=albums.id
INNER JOIN
songrating
ON
songs.id=songrating.songid
GROUP BY
songrating.songid
it only shows entries with at least one rating entry, but I also want these without a rating
I tried to use it with if / case but it doesn't work (or I'm doing something wrong)
If I remove the avg etc, it works correctly.
It may be JOIN issue
The INNER JOIN keyword selects all rows from both tables as long as there is a match between the columns in both tables.
The LEFT JOIN keyword returns all rows from the left table (table1), with the matching rows in the right table (table2). The result is NULL in the right side when there is no match.
Try LEFT JOIN

MySQL Multiple Joins in one query?

I have the following query:
SELECT
dashboard_data.headline,
dashboard_data.message,
dashboard_messages.image_id
FROM dashboard_data
INNER JOIN dashboard_messages
ON dashboard_message_id = dashboard_messages.id
So I am using an INNER JOIN and grabbing the image_id. So now, I want to take that image_id and turn it into images.filename from the images table.
How can I add that in to my query?
You can simply add another join like this:
SELECT dashboard_data.headline, dashboard_data.message, dashboard_messages.image_id, images.filename
FROM dashboard_data
INNER JOIN dashboard_messages
ON dashboard_message_id = dashboard_messages.id
INNER JOIN images
ON dashboard_messages.image_id = images.image_id
However be aware that, because it is an INNER JOIN, if you have a message without an image, the entire row will be skipped. If this is a possibility, you may want to do a LEFT OUTER JOIN which will return all your dashboard messages and an image_filename only if one exists (otherwise you'll get a null)
SELECT dashboard_data.headline, dashboard_data.message, dashboard_messages.image_id, images.filename
FROM dashboard_data
INNER JOIN dashboard_messages
ON dashboard_message_id = dashboard_messages.id
LEFT OUTER JOIN images
ON dashboard_messages.image_id = images.image_id
Just add another join:
SELECT dashboard_data.headline,
dashboard_data.message,
dashboard_messages.image_id,
images.filename
FROM dashboard_data
INNER JOIN dashboard_messages
ON dashboard_message_id = dashboard_messages.id
INNER JOIN images
ON dashboard_messages.image_id = images.image_id
I shared my experience of using two LEFT JOINS in a single SQL query.
I have 3 tables:
Table 1) Patient consists columns PatientID, PatientName
Table 2) Appointment consists columns AppointmentID, AppointmentDateTime, PatientID, DoctorID
Table 3) Doctor consists columns DoctorID, DoctorName
Query:
SELECT Patient.patientname, AppointmentDateTime, Doctor.doctorname
FROM Appointment
LEFT JOIN Doctor ON Appointment.doctorid = Doctor.doctorId //have doctorId column common
LEFT JOIN Patient ON Appointment.PatientId = Patient.PatientId //have patientid column common
WHERE Doctor.Doctorname LIKE 'varun%' // setting doctor name by using LIKE
AND Appointment.AppointmentDateTime BETWEEN '1/16/2001' AND '9/9/2014' //comparison b/w dates
ORDER BY AppointmentDateTime ASC; // getting data as ascending order
I wrote the solution to get date format like "mm/dd/yy" (under my name "VARUN TEJ REDDY")
Multi joins in SQL work by progressively creating derived tables one after the other.
See this link explaining the process:
https://www.interfacett.com/blogs/multiple-joins-work-just-like-single-joins/