MYSQL join not bringing correct result - mysql

I have created the following query which includes 2 joins and is working fine:
SELECT a.name, b.tid
FROM table1 a INNER JOIN
table2 b
ON a.id = b.id
INNER JOIN (
SELECT b2.id, b2.status, MAX(b2.created_time) as max_time
FROM oac.qualys_scan b2
GROUP BY b2.id , b2.qualys_type
) t on t.id = a.id
AND t.status=b.status
AND t.max_time = b.created_time
WHERE b.status = 'FAIL';
The output is coming as follows:
id tid name
17695 19512 abc.com
17781 19628 abc1.com
17805 19732 abc2.com
17806 19703 abc3.com
17807 19704 abc4.com
I have another table table3 which has following values
id tid name details
842 19512 abc.com Details Description 1
843 19628 abc1.com Details Description 2
I want to join the above query with table3 on tid such that I get the following output
id tid name details
17695 19512 abc.com Details Description 1
17781 19628 abc1.com Details Description 1
I am using the following query but it is returning only one row which is not correct
SELECT a.name, b.tid
FROM table1 a INNER JOIN
table2 b
ON a.id = b.id
INNER JOIN (
SELECT b2.id, b2.status, MAX(b2.created_time) as max_time
FROM oac.qualys_scan b2
GROUP BY b2.id , b2.qualys_type
) t on t.id = a.id
AND t.status=b.status
AND t.max_time = b.created_time
INNER JOIN table3 T3 on b.tid = T3.tid
WHERE b.status = 'FAIL'

Make your query a sub-query and join it to the table
WITH BASELINE AS
(
SELECT a.name AS name, b.tid AS tid
FROM table1 a INNER JOIN
table2 b
ON a.id = b.id
INNER JOIN (
SELECT b2.id, b2.status, MAX(b2.created_time) as max_time
FROM oac.qualys_scan b2
GROUP BY b2.id , b2.qualys_type
) t on t.id = a.id
AND t.status=b.status
AND t.max_time = b.created_time
WHERE b.status = 'FAIL';
)
-------------------------------------------------------------------
SELECT
base.tid
, base.name
, t3.details
FROM
BASELINE base
LEFT JOIN
Table3 t3
ON base.tid = t3.tid
Is not the neatest solution but it always works for me

Related

I was trying to intersect to table but it throws an error that 'intersect' is not valid at this position expecting EOF, ';'

SELECT id
, name
, bonus
FROM table1 a
LEFT
JOIN table2 b
ON a.id = b.employee_id
intersect
SELECT id
, name
, bonus
FROM table1 a
RIGHT
JOIN table2 b
ON a.id = b.employee_id;
SELECT tab1.id,tab1.name,tab1.bonus (SELECT id
, name
, bonus
FROM table1 a
LEFT
JOIN table2 b
ON a.id = b.employee_id) as tab1
INNER JOIN
(SELECT id
, name
, bonus
FROM table1 a
RIGHT
JOIN table2 b
ON a.id = b.employee_id) as tab2 ON tab1.id=tab2.id;
You can try like this

MYSQL Using Union to combine two queries

My first query looks as below
SELECT a.name, b.desc, T3.desc1 as Output
FROM table1 a INNER JOIN
table2 b
ON a.id = b.id
INNER JOIN (
SELECT b2.id, b2.status, MAX(b2.created_time) as max_time
FROM oac.qualys_scan b2
GROUP BY b2.id , b2.qualys_type
) t on t.id = a.id
AND t.status=b.status
AND t.max_time = b.created_time
INNER JOIN table3 T3 on b.tid = T3.tid
WHERE b.status = 'FAIL'
AND b.type = 'Type1'
My second query looks as below
SELECT a.name, b.desc, T4.desc2 as Output
FROM table1 a INNER JOIN
table2 b
ON a.id = b.id
INNER JOIN (
SELECT b2.id, b2.status, MAX(b2.created_time) as max_time
FROM oac.qualys_scan b2
GROUP BY b2.id , b2.qualys_type
) t on t.id = a.id
AND t.status=b.status
AND t.max_time = b.created_time
INNER JOIN table4 T4 on b.tid = T4.tid
WHERE b.status = 'FAIL'
AND b.type = 'Type2'
In my final result I want Output column which will have values either from T3.desc1 or T4.desc2
How can I use UNION to combine both queries into a single query?
just put UNION ALL between the queries. Youll have to alias the columns
Do this:
Query1 UNION Query2; -- for union without duplicates (the set union as in maths)
OR
Query1 UNION ALL Query2; -- for union with duplicates
So it should be:
SELECT a.name, b.desc, T3.desc1 as Output
FROM table1 a INNER JOIN
table2 b
ON a.id = b.id
INNER JOIN (
SELECT b2.id, b2.status, MAX(b2.created_time) as max_time
FROM oac.qualys_scan b2
GROUP BY b2.id , b2.qualys_type
) t on t.id = a.id
AND t.status=b.status
AND t.max_time = b.created_time
INNER JOIN table3 T3 on b.tid = T3.tid
WHERE b.status = 'FAIL'
AND b.type = 'Type1'
UNION
SELECT a.name, b.desc, T4.desc2 as Output
FROM table1 a INNER JOIN
table2 b
ON a.id = b.id
INNER JOIN (
SELECT b2.id, b2.status, MAX(b2.created_time) as max_time
FROM oac.qualys_scan b2
GROUP BY b2.id , b2.qualys_type
) t on t.id = a.id
AND t.status=b.status
AND t.max_time = b.created_time
INNER JOIN table4 T4 on b.tid = T4.tid
WHERE b.status = 'FAIL'
AND b.type = 'Type2';

MySQL combining two queries into single query

My first query looks as below
SELECT a.name, b.desc, T3.desc1 as Output
FROM table1 a INNER JOIN
table2 b
ON a.id = b.id
INNER JOIN (
SELECT b2.id, b2.status, MAX(b2.created_time) as max_time
FROM q_scan b2
GROUP BY b2.id , b2.qualys_type
) t on t.id = a.id
AND t.status=b.status
AND t.max_time = b.created_time
INNER JOIN table3 T3 on b.tid = T3.tid
WHERE b.status = 'FAIL'
My second query looks as below
SELECT a.name, b.desc, T4.desc2 as Output
FROM table1 a INNER JOIN
table2 b
ON a.id = b.id
INNER JOIN (
SELECT b2.id, b2.status, MAX(b2.created_time) as max_time
FROM q_scan b2
GROUP BY b2.id , b2.qualys_type
) t on t.id = a.id
AND t.status=b.status
AND t.max_time = b.created_time
INNER JOIN table4 T4 on b.tid = T4.tid
WHERE b.status = 'FAIL'
In my final result I want Output column which will have values either from T3.desc1 or T4.desc2
How can I combine both queries into a single query?
If the table2.id exists in one of the tables - table3 or table4, a LEFT JOIN will simplify the query with the help of IFNULL().
SELECT a.name,
b.desc,
IFNULL(T3.desc1, T4.desc2) as Output
FROM table1 a
INNER JOIN table2 b ON a.id = b.id
INNER JOIN
(
SELECT b2.id, b2.status, MAX(b2.created_time) as max_time
FROM oac.qualys_scan b2
GROUP BY b2.id , b2.qualys_type
) t on t.id = a.id
AND t.status=b.status
AND t.max_time = b.created_time
LEFT JOIN table3 T3 on b.tid = T3.tid
LEFT JOIN table4 T4 on b.tid = T4.tid
WHERE b.status = 'FAIL'

can't specify target table for UPDATE in FROM clause

I am trying to execute the following query:
update table3 d set status = 'Complete'
where d.id in
(
select b.id from table1 a, table3 b, table2 c
where a.id = b.table1_id
and c.id = b.table2_id
and c.examId = 16637 -- will be passed in by user
and a.id in (46,47,48,49) -- will be passed in by user
);
So, I'm trying to update multiple rows of table3.
table3 is a join table between table1 and table2.
wrap it in a subquery, (thus creating a temporary table for the result). I'm also recommending to use ANSI SQL-92 format.
update table3 d
set status = 'Complete'
where d.id in
(
SELECT ID
FROM
(
select b.id
from table1 a
INNER JOIN table3 b
ON a.id = b.table1_id
INNER JOIN table2 c
ON c.id = b.table2_id
where c.examId = 16637 and
a.id in (46,47,48,49)
) xx
);
or by using JOIN
update table3 d
INNER JOIN
(
SELECT ID
FROM
(
select b.id
from table1 a
INNER JOIN table3 b
ON a.id = b.table1_id
INNER JOIN table2 c
ON c.id = b.table2_id
where c.examId = 16637 and
a.id in (46,47,48,49)
) xx
) y ON d.id = y.id
set status = 'Complete'

Status table join for multiple states

I have two tables, A and B, A contains a list of entries and B for each of those entries multiple status rows (0-n, grouped by date with a status 0 for okay and 1 for failure).
Now I would like to select all rows from A with their respective most recent status and its date as well as the most recent failure and its date (failure defined as having at least one entry with 1).
I tried something with two left joins but am not convinced it is the optimal solution and also still have issues with determining the correct number of failures (SUM(b2.status))
SELECT a.id, b1.date, SUM(b1.status), b2.date, SUM(b2.status) FROM tablea a
LEFT JOIN tableb b1 ON b1.aid=a.id
LEFT JOIN tableb b2 ON b2.aid=a.id
WHERE (b1.date=(SELECT MAX(`date`) FROM tableb WHERE aid=a.id) OR b1.date IS NULL)
AND (b2.date=(SELECT MAX(`date`) FROM tableb WHERE aid=a.id GROUP BY `date` HAVING SUM(`status`)>0) OR b2.date IS NULL)
GROUP BY a.id
Whoops, I think every assumption I made to this point has been wrong. I think this will give you what you want. It will give you the total number of failures for the latest date that had a failure.
I'm not sure how performance will be on a very large database, but it works fine on a smaller one.
SELECT a.id, MAX(b1.date) status_date, SUM(b1.status) latest_status,
b2.date latest_failure,
b2.total_failures
FROM tablea a
LEFT JOIN tableb b1
ON b1.aid = a.id
AND b1.date = (SELECT MAX(date) FROM tableb WHERE aid = a.id)
LEFT JOIN
(SELECT aid, date, count(*) total_failures FROM tableb WHERE status > 0 GROUP BY aid, date) b2
ON b2.aid = a.id
AND b2.date = (SELECT MAX(date) FROM tableb WHERE aid = a.id AND status > 0)
GROUP BY a.id;
Something like this should work.
SELECT a.id, b1.date status_date, b1.status, b2.date latest_failure,
(SELECT COUNT(*) FROM tableb WHERE aid = a.id AND status > 0) total_failures
FROM tablea a
LEFT JOIN tableb b1
ON b1.aid = a.id
AND b1.date = (SELECT MAX(date) FROM tableb WHERE aid = a.id)
LEFT JOIN tableb b2
ON b2.aid = a.id
AND b2.date = (SELECT MAX(date) FROM tableb WHERE aid = a.id AND status > 0)
This is assuming that the tableb.date field is a datetime and is unique. Otherwise you may wish to use an id field instead.
You could do this also. Not sure which one is more efficient. You could try it both ways.
SELECT a.id, b1.date status_date, b1.status,
(SELECT MAX(date) FROM tableb WHERE aid = a.id AND status > 0) latest_failure,
(SELECT COUNT(*) FROM tableb WHERE aid = a.id AND status > 0) total_failures
FROM tablea a
LEFT JOIN tableb b1
ON b1.aid = a.id
AND b1.date = (SELECT MAX(date) FROM tableb WHERE aid = a.id)
This should work.
SELECT a.id, MAX(b1.date) status_date, SUM(b1.status) latest_status,
(SELECT MAX(date) FROM tableb WHERE aid = a.id AND status > 0) latest_failure,
(SELECT COUNT(*) FROM tableb WHERE aid = a.id AND status > 0) total_failures
FROM tablea a
LEFT JOIN tableb b1
ON b1.aid = a.id
AND b1.date = (SELECT MAX(date) FROM tableb WHERE aid = a.id)
GROUP BY a.id;
If you could have multiple failures for a day, and want to show the status as "1", then change this:
SUM(b1.status) latest_status
to:
MAX(b1.status) latest_status.