Join based on conditions - mysql

I have long hive query, which has 10 joins and lots of conditions, below is 3 conditions
1) If id is not equal to XFG or GHT, use field sid
join ABC_Tables on sid
join CDE_Tables on sid
2) If id is equal to XFG or GHT, Tested is null, use field pid
join ABC_Tables on kid
join CDE_Tables on kid
3) If id is equal to XFG or GHT, Tested is not null, use field pid
join ABC_Tables on kid
join CDE_Tables on kid
What am I doing,
select 1 conditions
union all
select 2 conditions
union all
select 3 conditions
am I doing right. What is the alternative of above problem.

Your conditions are allowed to be part of ON join condition. Equal/not equal to constants are allowed in Hive ( ID!='XFG')and(ID!='GHT')and(a.PID=b.PID) is allowed join condition. a.ID not in ('XFG', 'GHT') and a.sid=b.sid also should work:
select *
from a
left join b on a.ID not in ('XFG', 'GHT') and a.sid=b.sid
left join b on a.ID in ('XFG', 'GHT') and Tested is null and a.pid=b.pid

Related

how to use full outer join by removing inner join

I am new to MySQL I have one query which works perfectly fine with inner join but with inner join some records got missing I want all the data from both the table but when i use full outer join or full join it gives error unknown column classroom.id in field list
here is the query
SELECT
classroom.id as id,
classroom.grade as grade,
classroom.status as status,
teacher.id as tid,
teacher.name as tname
FROM classroom
FULL JOIN teacher on classroom.teacherId = teacher.id
ORDER BY grade ASC
these are my two tables you can see in the picture enter image description here
and also I mention in column
classroom
id,grade,teacherid,status
teacher
id,email,password,name,status,role
MySQL does not support a FULL OUTER JOIN or FULL JOIN, you have to emulate it using UNION with LEFT JOIN and RIGHT JOIN.
Read more about it here: Why does MySQL report a syntax error on FULL OUTER JOIN?
So your syntax should look like this:
SELECT * FROM
(SELECT
a.id as id,
a.grade as grade,
a.status as status,
b.id as tid,
b.name as tname
FROM classroom a
LEFT JOIN teacher b ON a.teacherId = b.id
UNION
SELECT
a.id as id,
a.grade as grade,
a.status as status,
b.id as tid,
b.name as tname
FROM classroom a
RIGHT JOIN teacher b ON a.teacherId = b.id) c
WHERE c.grade != '' AND c.grade IS NOT NULL
ORDER BY c.grade ASC
UPDATE: Per your comments below, I've include a WHERE clause to remove NULL values AND empty '' values. You could also write a WHERE clause in each of the UNION queries above but I find it easier to put it in a subquery and write the WHERE clause once in the outer query. I've also added aliases a, b, c so its easier to read vs. using the table names.
Demo here.

All my derived tables have aliases! Why am I getting 'Error 1248: Every derived table must have it's own alias'?

Every time I run this query, I get:
ERROR 1248 (42000): Every derived table must have its own alias
As you can see, we have a parent query which left joins against a derived table created by a subquery.
This subquery in turn selects from a second derived table, and inner joins a third derived table.
All three derived table have proper aliases (n1, n2 and subquery)
The subquery executes as expected when I execute it independently. The issue only occurs when I wrap it in the parent query.
Query:
SELECT DATE_FORMAT(p.date_admitted, '%Y-%m') as month_admitted,
diagnosis as diagnosis,
education as education,
COUNT(*) as total
FROM patient_discharge_form d
INNER JOIN survey_data sd ON sd.id = d.id
LEFT JOIN submission s ON s.id = sd.submission_id
LEFT JOIN patient p ON p.id = s.patient_id
LEFT JOIN (
SELECT n1.id,n1.diagnosis,n2.education
FROM (
SELECT id,'Gest Hyp' as diagnosis FROM patient_discharge_form WHERE gestational_hypertension=1
UNION ALL
SELECT id,'Pre w/ Sev' FROM patient_discharge_form WHERE preeclampsia_non_severe=1
) n1
INNER JOIN (
SELECT id,'Written' as education FROM patient_discharge_form WHERE education LIKE '%written%'
UNION ALL
SELECT id,'Verbal' FROM patient_discharge_form WHERE education LIKE '%verbal%'
) n2 ON n1.id=n2.id
) subquery ON d.id = subquery.id
WHERE (s.status = 'complete')
GROUP BY month_admitted, diagnosis, education
Hmmm . . . I don't see a problem with the table aliases in the query. I wonder if this is exactly the query you are running.
However, I do see a problem with the column aliases. The education column in the select (and perhaps diagnosis as well) is ambiguous. It could come from either d or subquery and perhaps other tables as well.
In general, you should qualify all column names in a query to avoid problems.

Get only last record of JOIN in MySQL

I have 2 tables A, B where B contains a foreign key to A
ida,cola1
idb,fka,colb1
For each record from A I need to get only the last result of LEFT OUTER JOIN. The following query displays all JOINs, how to limit it to the last occurence of fka only?
SELECT ida,idb,cola1,colb1 FROM a LEFT OUTER JOIN b ON ida=fka
If the last result in table b is the one with the highest idb, then one solution is to use a subquery where you calculate max(idb) for each fka:
select
a.ida,
a.cola1,
b.idb,
b.fka,
b.colb1
from
a left outer join (
select fka, max(idb) as max_idb
from b
group by fka
) max_b on a.ida=max_b.fka
left outer join b on max_b.fka=b.fka and max_b.max_idb=b.idb
You can use group by to remove all other columns from the table B
then join the to the table A to get the result
Group by requires an aggregate function like min or max etc
Here I tried it with min
SELECT
ida, idb, cola1, colb1
FROM A LEFT OUTER JOIN (
select
min(idb) idb, fka, min(colb1) colb1
from B
group by fka
) b
ON ida = fka
SELECT
ida,idb,cola1,colb1
FROM a
LEFT OUTER JOIN b ON ida=fka
ORDER BY ida DESC LIMIT 1
May Be this one is Help you.

Excluding MYSQL query results with an INNER JOIN

I have two tables. The first is full of books each with a book_id. The second table is a book_id to keyword_id relationship table.
SELECT b.* FROM books_table b
INNER JOIN keywords_table k
ON b.book_id = k.book_id AND k.keyword_id NOT IN(1,2,3)
WHERE b.is_hardcover = 1
GROUP BY b.book_id
Desired Outcome
No books with the keyword_id 1, 2, or 3 attached to any of the books.
Actual Outcome
Books can have the keywords 1, 2, or 3 so long as they have additional keyword_ids attached to them that are not in the exclusion list.
What I've tried
The above query is the closest I have come to achieving it, but it fails in this one regard.
How can I achieve the desired outcome and in the most optimized way?
You can do so
SELECT b.*
FROM books_table b
INNER JOIN keywords_table k
ON b.book_id = k.book_id
WHERE b.is_hardcover = 1
GROUP BY b.book_id
HAVING SUM(k.keyword_id = 1) =0
AND SUM(k.keyword_id = 2) =0
AND SUM(k.keyword_id = 3) =0
As you noted, this query will produce any book that has at least one keyword that isn't 1, 2 or 3, which isn't what you want. Instead, you'd want to explicitly exclude books with these keywords. A join isn't really the right took for the job here. Instead, you could use the exists operator:
SELECT b.*
FROM books_table b
WHERE b.is_hardcover = 1 AND
NOT EXISTS (SELECT *
FROM keywords_table k
WHERE b.book_id = k.book_id AND
k.keyword_id IN (1,2,3))
What you are asking for is a flavor of "anti join". There are several ways to accomplish it; here's one:
SELECT b.* FROM books_table b
LEFT JOIN keywords_table k
ON b.book_id = k.book_id AND k.keyword_id IN (1,2,3)
WHERE k.book_id IS NULL AND b.is_hardcover = 1
The left join matches up each row from the left table (books_table) with those rows of the right table that satisfy the condition b.book_id = k.book_id AND k.keyword_id IN (1,2,3), and includes a single result row for each row of the left table that doesn't match any row of the right table. The filter condition k.book_id IS NULL conflicts with the join condition, so it can be satisfied only by those rows arising from a left row not matching any right row.
Note that the assignment of conditions to the join predicate and the filter predicate is critical with an outer join such as this one. Note also that there is no need for a GROUP BY clause in this case unless books_table may contain duplicate book_ids.
This approach is likely to perform better in practice than one based on a correlated subquery in the WHERE clause. If performance is important, however, then you would be well advised to test the alternatives you are considering.
You can use the following query:
SELECT *
FROM books_table
WHERE is_hardcover = 1 AND
book_id NOT IN (SELECT book_id
FROM keywords_table
GROUP BY book_id
HAVING COUNT(CASE WHEN keyword_id IN (1,2,3) THEN 1 END) <> 0)
Demo here

Counting in Many to Many Relations in SQL

I have a table A and B, and their many to many relations in table AB.
Select A.id, AB.bId FROM A LEFT JOIN AB on A.id = AB.aId
gives
A1--B1
A1--B2
A2--B3
A3--NULL
A4--B4
I want to find total number of distict A's and total number of distinct A's having a not null B. e.g. for above table, the numbers and 4 and 3. In fact, I am wondering the percentage 3/4=0.75.
Can I do this in one optimal query?
Since count() does not count null, you could:
select count(distinct A.id) as DistinctA
, count(distinct case
when AB.bId is not null then A.id
end) as DistinctAHavingNotNullB
from A
left join
AB
on A.id = AB.aId
Note that a case without else returns null when no when clause matches.