Combining multiple queries into a single one - mysql

I have a simple query:
SELECT t1.tbl,
t1.slug
FROM t1
WHERE tags = '%".$tag."%'
However, I need to augment my results with the data from other tables (t2, t3, t4 and t5).
For example, if t1.tbl = 't2' I need to add from:
SELECT t2.title
FROM t2
WHERE t2.county = '".$county."'
which I could join like this:
LEFT JOIN ON (t1.rid = t2.id)
In each of there tables I'll filter by $county even though the column is named differently.
I've tried something like this:
SELECT t1.tbl,
t1.slug
FROM t1 A
LEFT JOIN (
SELECT title
FROM t2 B
WHERE A.tbl = 't2'
) ON (A.rid = B.id)
WHERE A.tags = '%".$tag."%'
Is there a way to combine all there into a single query?

SELECT A.tbl,
A.slug,
COALESCE(B.title, C.title) AS title
FROM t1 A
LEFT JOIN t2 B
ON A.tbl = 't2' AND A.rid = B.id AND B.county = ?
LEFT JOIN t3 C
ON A.tbl = 't3' AND A.rid = C.id AND C.region = ?
WHERE A.tags LIKE ?
AND COALESCE(B.id, C.id) IS NOT NULL;
The last condition is to return only rows from A that have a match among one of the joined tables.
I think that's enough to see the pattern, so you can add more tables.
I urge you to learn to use query parameters instead of concatenating variables directly into your SQL string. It's easier to write the code and more secure from SQL injection vulnerabilities if you use query parameters.

Related

Create View by Left join on multiple columns with OR

I am trying to create a view from two tables by left joining on two columns: t1.recipient_email = t2.username or t1.created_by = t2.id. As shown in pseudocode below, I want the first t2.name to be the recipient_name and second t2.name to be sender_name. I can't think of the correct way to achieve this.
CREATE VIEW emailsent_log_view
(id_email_que_log, date_sent, recipent_email, recipient_name, send_status, sender_name)
AS
SELECT
t1.id,
t1.date_send,
t1.recipient_email,
t2.name, --recipient_name: corresponds with t1.recipient_email = t2.username
t1.send_status,
t2.name --sender_name: correspond with t1.created_by = t2.id
FROM email_que_log AS t1
LEFT JOIN user_account as t2
ON t1.recipient_email = t2.username
OR t1.created_by = t2.id
As you guessed, you can't pick and choose which row joins to which row with an or condition like that. The way to solve such issues is to join the table twice, once for each need:
CREATE VIEW emailsent_log_view
(id_email_que_log, date_sent, recipent_email, recipient_name, send_status, sender_name)
AS
SELECT
eql.id,
eql.date_send,
eql.recipient_email,
res.name AS reciever, -- From the first join
eql.send_status,
snd.name AS sender -- From the second join
FROM
email_que_log AS eql
LEFT JOIN
user_account AS res ON eql.recipient_email = res.username
LEFT JOIN
user_account AS snd ON eql.created_by = snd.id

why is left join so slow in mysql

I am new in programming. A have a query which sometimes works but sometimes doesn't works at all. I mean if the result is not only a row it become too slow. If the result is several hundred rows it doesn't works at all. I know it's not the best to use 'like' in the query but I have no other options (or I just don't know).
Please help me to optimize my query.
I should run this query with different "where" options (the first part would be always the same). Shall I store the first part in a function? Does it make the query faster?
SELECT a.*,
group_concat(DISTINCT concat(' ', b.name)),
group_concat(DISTINCT concat(' ', e.name)),
group_concat(DISTINCT concat(' ', g.name))
FROM t1 a
LEFT JOIN t2 c
INNER JOIN t3 b ON c.id = b.id ON a.id = c.id
LEFT JOIN t4 d
INNER JOIN t5 e ON e.code = d.code ON a.id = d.id
LEFT JOIN t6 f
INNER JOIN t7 g ON g.code = f.code ON a.id = f.id
WHERE a.x LIKE '%5%'
GROUP BY a.id;
Thank you in advance!
A join without condition is a cross join. In your query there are three such joins: t2, t4, t6 tables. A CROSS JOIN is a JOIN operation that produces the Cartesian product of two tables. It will produce rows which combine each row from the first table with each row from the second table. The performance is poor because cross join produces too many rows. See documentation: https://www.w3resource.com/sql/joins/cross-join.php
if a.x is a varchar field use something like
Full-Text Index
I 'm not sure if mysql has it but give it a try
This is what I use in SQL Server

MySQL - Joining table on itself based on criteria from other table

Here’s the problem I am trying to solve:
Table1 has Product ID’s, dates, and prices for those dates, Table2 has Product attributes.
I want to be able to compare prices for a client for different products on the same date based on a set of attributes. I’m easily able to get a list of products/dates/prices for a ‘simple’ product, as well as an ‘advanced’ product (see below).
I want to be able to join these two tables such that the output looks like:
[CLIENT] [PRODUCT] [DATE] [SIM_PROD] [SIM_PRICE] [ADV_PROD] [ADV_PRICE]
Here is as far as I've made it
SELECT b.NAME AS ‘CLIENT’, a.NAME AS ‘SIMPLE_PRODUCT’, t1.DATE AS ‘DATE’, t1.PIVOT_PRICE AS ‘SIMPLE_PRICE’
FROM TABLE1 t1
LEFT JOIN PRODUCT a
ON t1.PRODUCT_ID = a_PRODUCT_ID
LEFT JOIN CLIENTS b
ON a.PARTNER_ID = b.PARTNER_ID
WHERE a.CRITERIA = TRUE;
SELECT b.NAME AS ‘CLIENT’, a.NAME AS ‘ADV_PRODUCT’, t2.DATE AS ‘DATE’, t2.PIVOT_PRICE AS ‘ADV_PRICE’
FROM TABLE1 t2
LEFT JOIN PRODUCT a
ON t2.PRODUCT_ID = a_PRODUCT_ID
LEFT JOIN CLIENTS b
ON a.PARTNER_ID = b.PARTNER_ID
WHERE a.CRITERIA = FALSE;
I've been able to build similar tables where I pull in price from TABLE1 labeling it as t1 then pull in price again from TABLE1 and labeling it as t2, but only when using criteria in TABLE1, not criteria in a table that needs to be joined.
Is it possible to 'set' a table (EG simple) then 'set' a second one (EG advanced) and then join them on PARTNER_ID and DATE?
You can join the two subqueries:
SELECT t1.client, t1.date, t1.simple_product, t1.simple_price, t2.adv_product, t2.adv_price
FROM (
SELECT b.NAME AS CLIENT, a.NAME AS SIMPLE_PRODUCT, t1.DATE, t1.PIVOT_PRICE AS SIMPLE_PRICE
FROM TABLE1 t1
LEFT JOIN PRODUCT a
ON t1.PRODUCT_ID = a_PRODUCT_ID
LEFT JOIN CLIENTS b
ON a.PARTNER_ID = b.PARTNER_ID
WHERE a.CRITERIA = TRUE
) AS t1
JOIN (
SELECT b.NAME AS CLIENT, a.NAME AS SIMPLE_PRODUCT, t1.DATE, t1.PIVOT_PRICE AS SIMPLE_PRICE
FROM TABLE1 t1
LEFT JOIN PRODUCT a
ON t1.PRODUCT_ID = a_PRODUCT_ID
LEFT JOIN CLIENTS b
ON a.PARTNER_ID = b.PARTNER_ID
WHERE a.CRITERIA = FALSE
) AS t2
ON t1.client = t2.client AND t1.date = t2.date
You'll probably need to select additional criteria and add them to the ON condition. Otherwise this will produce a full cross product between all the products that have the same client and date.
Your desired output has an additional PRODUCT column, but I couldn't see where that comes from.

INNER JOIN with more than one OR operators in WHERE clause increases the execution time

as we know - "INNER JOIN with complex condition dramatically increases the execution time please refer this"
consider the query
(
SELECT ...
FROM Table1
INNER JOIN Table2 ON Table1.P1 = Table2.P1 OR Table1.P2 = Table2.P2
)
Over here comparison will be done via "nested loops" so execution time will be more but if we have a query like-
(
SELECT ...
FROM Table1
INNER JOIN Table2 ON Table1.P3 = Table2.P3 where Table1.P1 = "abc" OR
Table2.p2 = "xyz"
)
or like-
(
SELECT ...
FROM Table1
INNER JOIN Table2 ON Table1.P3 = Table2.P3 where Table1.P1 LIKE "abc" OR
Table2.p2 LIKE "xyz"
)
than also does the comparison will take place through nested loops only (for columns P1 ANd P2)?
Please Use Union instead of 'OR' condition in JOIN.
SELECT ...
FROM Table1
INNER JOIN Table2 ON Table1.P1 = Table2.P1
UNION All
SELECT ...
FROM Table1
INNER JOIN Table2 ON Table1.P2 = Table2.P2 AND Table1.P1 <> Table2.P1

Return zero or null when Joining 3 tables in mysql

I am trying to JOIN 3 Tables(table1, table2 & table3) in Mysql query where I want to pull the matching data from 2 tables(table1 & table2) comparing a Common Column existing in 3 tables(ie. 'PID').
When Joining these 3 tables, there is no data in table1 with the given Date('2012-12-27') then it's returning complete blank row.. Here, I want to get the matching data from the table2 matching the given Date and 'ZERO' or 'NULL' where there is no matching data in the other table ie. table1.. instead of a whole blank row.
Here is the code I was trying that returns a complete BLANK ROW..
SELECT * FROM table3 b
LEFT JOIN table1 r ON r.PID = b.PID
LEFT JOIN table2 a ON ab.PID = b.PID
WHERE b.Name ='stallion' AND r.Date = '2012-12-27' AND a.Date = '2012-12-27'
;
Use two different JOIN statement then UNION them.
The rows where there is no data in table1 (r) have r.Data = NULL and are therefore filtered away by your WHERE condition. You need to add OR r.Date IS NULL to your WHERE condition or move the condition to the ON clause:
SELECT * FROM table3 b
LEFT JOIN table1 r ON r.PID = b.PID AND r.Date = '2012-12-27'
LEFT JOIN table2 a ON a.PID = b.PID AND a.Date = '2012-12-27'
WHERE b.Name ='stallion';