How to subtract a query result from another query result in MYSQL - mysql

1st query
(SELECT a.cat_id,
a.cat_name,
a.cat_description,
b.subcat_name,
b.subcat_description
FROM trade_categories a
LEFT JOIN trade_subcategories b ON a.cat_id = b.cat_id
WHERE a.cat_name LIKE '%catty%'
OR a.cat_description LIKE '%catty%')
UNION
(SELECT c.cat_id,
d.cat_name,
d.cat_description,
c.subcat_name,
c.subcat_description
FROM trade_subcategories c
LEFT JOIN trade_categories d ON c.cat_id = d.cat_id
WHERE c.subcat_name LIKE '%catty%'
OR c.subcat_description LIKE '%catty%')
2nd query :
SELECT x.cat_id,
x.cat_name,
x.cat_description,
y.subcat_name,
y.subcat_description
FROM trade_categories x
JOIN trade_subcategories y ON x.cat_id = y.cat_id
WHERE ( x.cat_name LIKE '%catty%'
OR x.cat_description LIKE '%catty%' )
AND ( y.subcat_name NOT LIKE '%catty%'
OR y.subcat_description NOT LIKE '%catty%' )
I want to subtract the 2nd query result from 1st query result.

http://www.bitbybit.dk/carsten/blog/?p=71
or
example:
SELECT Name FROM employee1 WHERE name NOT IN (SELECT name FROM employee2);

I think you can either do a NOT IN or a LEFT JOIN. I'd prefer a LEFT JOIN.
So for example,
SELECT `QUERY_ONE`.*
FROM `QUERY_ONE`
LEFT JOIN `QUERY_TWO` USING (`cat_id`)
WHERE QUERY_TWO.cat_id IS NULL;
where QUERY_ONE and QUERY_TWO are aliases for your two queries

SELECT a.cat_id,
a.cat_name,
a.cat_description,
b.subcat_name,
b.subcat_description
FROM trade_categories a
LEFT JOIN trade_subcategories b ON a.cat_id = b.cat_id
WHERE a.cat_name NOT LIKE '%catty%'
AND a.cat_description NOT LIKE '%catty%'
AND (b.cat_id IS NULL
OR b.subcat_name NOT LIKE '%catty%' AND b.subcat_description NOT LIKE '%catty%')
Or, if the results of the two queries have been stored in (temporary) tables, you could use #Abhay's solution on them.

Related

Alternative to Where Exist clause MySQL

I have this select statement that is taking quite a while to run on a larger dataset
select lookup_svcscat_svcscatnew.SVCSCAT_NEW_DESC as svc_type,
enrolid, msclmid, dx1, dx2, dx3,
proc1,msk_cpt_mapping.surg_length_cd as SL_CD,
msk_cpt_mapping.days as day_window,o.svcdate_form, pay,
table_label
from ccaeo190_ky o
left join lookup_svcscat_svcscatnew on o.svcscat = lookup_svcscat_svcscatnew.svcscat
left join msk_cpt_mapping on o.proc1 = msk_cpt_mapping.cpt_code
where EXISTS
(
select 1
from eoc_op_mapping e
where e.msclmid = o.msclmid
and e.enrolid = o.enrolid
and proc1 =27447
)
ORDER BY svcdate_form, msclmid;
I want to return any row in my ccaeo190_ky table that meets the requirements of the where EXISTS clause on table eoc_op_mapping. Is there any way to achieve these results using joins or select statements?
I was thinking something like:
select lookup_svcscat_svcscatnew.SVCSCAT_NEW_DESC as svc_type,
o.enrolid, o.msclmid, dx1, dx2, dx3,
proc1,msk_cpt_mapping.surg_length_cd as SL_CD,
msk_cpt_mapping.days as day_window,o.svcdate_form, pay,
table_label
from ccaeo190_ky o
left join lookup_svcscat_svcscatnew on o.svcscat = lookup_svcscat_svcscatnew.svcscat
left join msk_cpt_mapping on o.proc1 = msk_cpt_mapping.cpt_code
inner join
(select msclmid, SUM(IF(proc1 = 27447,1,0)) AS cpt
from eoc_op_mapping
group by enrolid
HAVING cpt > 0) e
on e.enrolid = o.enrolid
group by o.enrolid;
But I don't know if this is in the right direction
Usually EXISTS performs better than a join.
If you want to try a join, this the equivalent to your WHERE EXISTS:
.......................................................
inner join (
select distinct msclmid, enrolid
from eoc_op_mapping
where proc1 = 27447
) e on e.msclmid = o.msclmid and e.enrolid = o.enrolid
.......................................................
You can remove distinct if there are no duplicate msclmid, enrolid combinations in eoc_op_mapping.

Select from three tables with same ID

I've three tables
students_first_semester_mark (StudentdID,Subject, Semester_I_Mark )
students_second_semester_mark (StudentdID,Subject, Semester_II_Mark )
students_third_semester_mark (StudentdID,Subject, Semester_III_Mark )
I want to have the following kind of output:
_________________________________________________________________________________
|StudentdID | Subject | Semester_I_Mark| Semester_II_Mark | Semester_III_Mark
_________________________________________________________________________________
Please note that Semester_I_Mark or Semester_II_Mark may have Null values.
I'm eager for your answers.
Is this what you want?
SELECT [students_first_semester_mark].[StudentdID]
,[students_first_semester_mark].[Subject]
,[students_first_semester_mark].[Semester_I_Mark]
,[students_second_semester_mark].[Semester_II_Mark]
,[students_third_semester_mark].[Semester_III_Mark]
FROM [students_first_semester_mark]
JOIN [students_second_semester_mark] ON [students_second_semester_mark].[StudentdID] = [students_first_semester_mark].[StudentdID]
JOIN [students_third_semester_mark] ON [students_third_semester_mark].[StudentdID] = [students_second_semester_mark].[StudentdID]
Below is the simplest answer that I can think of.
SELECT T1.StudentdID,T1.Subject,T1.Semester_I_Mark,
T2.Semester_II_Mark, T3.Semester_III_Mark
FROM students_first_semester_mark T1, students_second_semester_mark T2,
students_third_semester_mark T3
JOIN T2 ON T1.StudentdID = T2.StudentdID
JOIN T3 ON T1.StudentdID = T3.StudentdID
This might help you:
SELECT table1.StudentdID, table1.Subject,
table1.Semester_I_Mark, table2.Semester_II_Mark,
table3.Semester_III_Mark
FROM students_first_semester_mark table1
INNER JOIN students_second_semester_mark table2
ON table1.StudentdID = table2.StudentdID
INNER JOIN students_third_semester_mark table3
ON table1.StudentdID = table3.StudentdID
I am assuming that all students will not appear in all subjects.
It will be bit tricky to achieve it in MySQL as it doesn't support full outer join.
To derive FULL OUTER JOIN, you need a LEFT JOIN UNION RIGHT JOIN. As in your case, there are 3 tables, you would need to repeat this for first 2 tables and then UNION them. So the query will be pretty complex to look.
DBFiddle Demo
select * from (
select coalesce(fs.studentdid,t.studentdid) as STUDENTDID
,coalesce(fs.subject,t.subject) as subject
,fs.semester_i_mark,fs.semester_ii_mark,t.semester_iii_mark
from
(
select
coalesce(f.studentdid,s.studentdid) as STUDENTDID,
coalesce(f.subject,s.subject) as subject
,f.semester_i_mark,s.semester_ii_mark
from
STUDENTS_FIRST_SEMESTER_MARK f
left join
STUDENTS_SECOND_SEMESTER_MARK s
on f.studentdid=s.studentdid
and f.subject=s.subject
UNION
select
coalesce(f.studentdid,s.studentdid) as STUDENTDID,
coalesce(f.subject,s.subject) as subject
,f.semester_i_mark,s.semester_ii_mark
from
STUDENTS_FIRST_SEMESTER_MARK f
right join
STUDENTS_SECOND_SEMESTER_MARK s
on f.studentdid=s.studentdid
and f.subject=s.subject
) fs
LEFT JOIN
STUDENTS_THIRD_SEMESTER_MARK t
on fs.STUDENTDID=t.studentdid
and fs.subject=t.subject
) u1
UNION
select * from (
select coalesce(fs.studentdid,t.studentdid) as STUDENTDID
,coalesce(fs.subject,t.subject) as subject
,fs.semester_i_mark,fs.semester_ii_mark,t.semester_iii_mark
from
(
select
coalesce(f.studentdid,s.studentdid) as STUDENTDID,
coalesce(f.subject,s.subject) as subject
,f.semester_i_mark,s.semester_ii_mark
from
STUDENTS_FIRST_SEMESTER_MARK f
left join
STUDENTS_SECOND_SEMESTER_MARK s
on f.studentdid=s.studentdid
and f.subject=s.subject
UNION
select
coalesce(f.studentdid,s.studentdid) as STUDENTDID,
coalesce(f.subject,s.subject) as subject
,f.semester_i_mark,s.semester_ii_mark
from
STUDENTS_FIRST_SEMESTER_MARK f
right join
STUDENTS_SECOND_SEMESTER_MARK s
on f.studentdid=s.studentdid
and f.subject=s.subject
) fs
RIGHT JOIN
STUDENTS_THIRD_SEMESTER_MARK t
on fs.STUDENTDID=t.studentdid
and fs.subject=t.subject
) u2
Coalesce is used so that any not null values of studentdid and subject are returned as we are using outer join.

Mysql Query never stops

I have a simple table with 3 columns
PageDescription(varchar(50)) | ParentID (int) | CategoryID (int)
Here is the table data
Fruit||1
Apples|1|2
here is the query i'm running
SELECT PageDescription,(SELECT PageDescription
FROM tblpages a
WHERE a.ParentID = tblpages.CategoryID)
AS 'Page Parent'
FROM tblpages
This query does not stop processing, is there a better way to handle this query?
You can use a JOIN to perform this:
SELECT t1.PageDescription
, t2.PageDescription as PageParent
FROM t t1
LEFT JOIN t t2
on t1.ParentId = t2.CategoryId
See SQL Fiddle with Demo
Using a LEFT JOIN will allow you to include the items that have a null value.
What you need is a join.
SELECT a.PageDescription, b.PageDescription as Parent
FROM tblpages a
LEFT JOIN tblpages b ON a.CategoryID = b.ParentID
Try to name yout two tables:
SELECT b.PageDescription,(SELECT PageDescription
FROM tblpages a
WHERE a.ParentID = b.CategoryID)
AS 'Page Parent'
FROM tblpages b
SELECT p.PageDescription,p1.PageDescription
FROM tblpages p1
LEFT JOIN p2 on p1.parentId=p2.categoryID
WHERE 1;

Update statement with nested joins not working

I need to update multiple records in a table based upon the sum of some values in another table. Here is my query:
UPDATE aallinnot2 c SET c.Energ_Kcal = ( SELECT d.id1, SUM( c.Energ_Kcal)
FROM aaingred a
LEFT JOIN aaweight b ON a.unit = b.uni
LEFT JOIN aallinnot2 c ON a.mfdfsds = c.NDB_No
LEFT JOIN aalinfsds d ON a.fsdsnum = d.id1
WHERE d.own_id =42
GROUP BY id1 )
WHERE c.NDB_No
IN ( SELECT DISTINCT `fsdsnum`
FROM `aaingred`
WHERE `usernum` LIKE '42'
)
MySQL said:
#1093 - You can't specify target table 'c' for update in FROM clause
Unfortunately, I don't know how to get my values without referencing target table 'c'! Is there a workaround for this?
With the crazy table/column names and indecipherable logic, this might be the ugliest query I have ever seen. Congrats. :)
I think the following should work (or this approach). The main problem was untangling the group-by expression-- you need to give the database engine a dataset where each row in the target table is joined to a set that contains the updated value for that row. So here, select the new values in a sub-query, then join that sub-query to the original table.
EDIT Fixed some syntax
UPDATE
(
SELECT d.id1, SUM (c.Energ_Kcal) AS Sum_Energ_Kcal
FROM aaingred a
LEFT JOIN aaweight b ON a.unit = b.uni
LEFT JOIN aallinnot2 c ON a.mfdfsds = c.NDB_No
LEFT JOIN aalinfsds d ON a.fsdsnum = d.id1
WHERE d.own_id =42
GROUP BY id1
) d
,aaingred a, aallinnot2 d
SET Energ_Kcal = d.Sum_Energ_Kcal
WHERE d.id1 = a.fsdsnum
AND a.mfdfsds = aallinnot2.NDB_No
AND c.NDB_No IN (
SELECT DISTINCT `fsdsnum`
FROM `aaingred`
WHERE `usernum` LIKE '42'
);
I'm not sure about mysql, but with SQL Server the statement would be something like this:
UPDATE aallinnot2
SET Energ_Kcal = (
SELECT SUM( c.Energ_Kcal)
FROM aaingred a
LEFT JOIN aaweight b ON a.unit = b.uni
LEFT JOIN aallinnot2 c ON a.mfdfsds = c.NDB_No
LEFT JOIN aalinfsds d ON a.fsdsnum = d.id1
WHERE d.own_id =42)
WHERE c.NDB_No
IN ( SELECT DISTINCT `fsdsnum`
FROM `aaingred`
WHERE `usernum` LIKE '42')
You can't alias the table to be updated in the UPDATE clause, but you can in the FROM clause.

Troubles with nested queries

I have this query which works perfectly:
SELECT *
FROM Customer
WHERE SacCode IN
(
SELECT SacCode
FROM SacCode
WHERE ResellerCorporateID = 392
ORDER BY SacCode
)
AND CustomerID IN
(
SELECT CxID
FROM CustAppointments
WHERE AppRoomID IN
(
SELECT AppRoomID
FROM ClinicRooms
WHERE ClinID IN
(
SELECT ClinID
FROM AppClinics
WHERE ClinDate >='20090101'
AND ClinDate <='20091119'
)
)
)
However, I need to see the value of ClinDate (inside the last nested query)...
How do I do it?
Thanks.
I'd rewrite the query using joins. Then, you can access any data from any of the joined tables.
For example, you could rewrite your query like this:
SELECT c.*, ac.ClinDate
FROM Customer c
JOIN SacCode sc ON sc.SacCode = c.SacCode
JOIN CustAppointments ca ON ca.CustomerID = c.CustomerID
JOIN ClinicRooms cr ON cr.AppRoomID = ca.AppRoomID
JOIN AppClinic ac ON ac.ClinID = cr.ClinID
WHERE ac.ClinDate >='20090101'
AND ac.ClinDate <='20091119'
AND sc.ResellerCorporateID = 392
Think I'd use derived table in the FROM statement rather than 3 deep nested query, will allow you to access values and will look a LOT better.
You'll need to copy the subselects to the FROM clause or rewrite the query using JOINs.
it should look something like this:
SELECT c.*, a.ClinDate
FROM Customer c
inner join CustAppointments ca
inner join ClinicRooms cr
inner join AppClinics a
where c.SacCode IN
(
SELECT SacCode
FROM SacCode
WHERE ResellerCorporateID = 392
ORDER BY SacCode
)
and c.CustomerID = ca.CxID
and ca.AppRoomID = cr.AppRoomID
and cr.ClinID = a.ClinID
and a.ClinDate >='20090101'
and a.ClinDate <='20091119'