Troubles with nested queries - mysql

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'

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.

How do I make this complex query run faster?

This query is taking between 20-40 seconds to run. I need to speed it up greatly if possible.
SELECT DISTINCT a.category, a.key
FROM system_permissions AS a, system_permission_to_role AS b,
system_user_to_role AS c, system_users AS d
WHERE
(
(
a.system_permission_id=b.system_permission_id
AND (b.system_role_id=c.system_role_id || c.system_role_id = 0)
AND a.system_permission_id NOT IN (
SELECT system_permission_id FROM system_permission_exclusions AS f
WHERE d.system_user_id=f.system_user_id
)
AND c.system_user_id=d.system_user_id
)
OR a.system_permission_id IN (
SELECT system_permission_id
FROM system_permission_inclusions AS g
WHERE d.system_user_id=g.system_user_id
)
)
AND d.ldap_objectguid = '?';
The reason behind doing it this way is that I am creating exclusion and inclusion tables for permissions that fall outside of the standard defined roles, so first I need to exclude ones that are part of the role but exist in the exclusion table, then I need to add ones that are NOT part of their role, but exist in the inclusion table.
I am open to the idea of redesigning the tables also.
Does this work?
SELECT DISTINCT P.category, P.key
FROM system_users U
LEFT OUTER JOIN system_permission_inclusions PI ON PI.system_user_id = U.system_user_id
INNER JOIN system_user_to_role UR ON UR.system_user_id = U.system_user_id
INNER JOIN system_permission_to_role PR ON PR.system_role_id = UR.system_role_id
INNER JOIN system_permissions P ON P.system_permission_id = PR.system_permission_id OR P.system_permission_id = PI.system_permission_id
WHERE U.ldap_objectguid = '?'
AND P.system_permission_id NOT IN (SELECT system_permission_id FROM system_permission_exclusions WHERE system_user_id = U.system_user_id)

Mysql tekes too much time to excute sql query, based on multiple join

My Sql query takes more time to execute from mysql database server . There are number of tables are joined with sb_tblproperty table. sb_tblproperty is main table that contain more than 1,00,000 rows . most of table contain 50,000 rows.
How to optimize my sql query to fast execution. I have also used indexing.
indexing Explain - query - structure
SELECT `t1`.`propertyId`, `t1`.`projectId`,
`t1`.`furnised`, `t1`.`ownerID`, `t1`.`subType`,
`t1`.`fors`, `t1`.`size`, `t1`.`unit`,
`t1`.`bedrooms`, `t1`.`address`, `t1`.`dateConfirm`,
`t1`.`dateAdded`, `t1`.`floor`, `t1`.`priceAmount`,
`t1`.`priceRate`, `t1`.`allInclusive`, `t1`.`booking`,
`t1`.`bookingRate`, `t1`.`paidPercetage`,
`t1`.`paidAmount`, `t1`.`is_sold`, `t1`.`remarks`,
`t1`.`status`, `t1`.`confirmedStatus`, `t1`.`source`,
`t1`.`companyName` as company, `t1`.`monthly_rent`,
`t1`.`per_sqft`, `t1`.`lease_duration`,
`t1`.`lease_commencement`, `t1`.`lock_in_period`,
`t1`.`security_deposit`, `t1`.`security_amount`,
`t1`.`total_area_leased`, `t1`.`lease_escalation_amount`,
`t1`.`lease_escalation_years`, `t2`.`propertyTypeName` as
propertyTypeName, `t3`.`propertySubTypeName` subType,
`t3`.`propertySubTypeId` subTypeId, `Owner`.`ContactName`
ownerName, `Owner`.`companyName`, `Owner`.`mobile1`,
`Owner`.`otherPhoneNo`, `Owner`.`mobile2`,
`Owner`.`email`, `Owner`.`address` as caddress,
`Owner`.`contactType`, `P`.`projectName` as project,
`P`.`developerName` as developer, `c`.`name` as city,
if(t1.projectId="", group_concat( distinct( L.locality)),
group_concat( distinct(L2.locality))) as locality, `U`.`firstname`
addedBy, `U1`.`firstname` confirmedBy
FROM `sb_tblproperty` as t1
JOIN `sb_contact` Owner ON `Owner`.`id` = `t1`.`ownerID`
JOIN `tbl_city` C ON `c`.`id` = `t1`.`city`
JOIN `sb_propertytype` t2 ON `t1`.`propertyType`= `t2`.`propertyTypeId`
JOIN `sb_propertysubtype` t3 ON `t1`.`subType` =`t3`.`propertySubTypeId`
LEFT JOIN `sb_tbluser` U ON `t1`.`addedBy` = `U`.`userId`
LEFT JOIN`sb_tbluser` U1 ON `t1`.`confirmedBy` = `U1`.`userId`
LEFT JOIN `sb_tblproject` P ON `P`.`id` = `t1`.`projectId` LEFT
JOIN `sb_tblpropertylocality` PL ON `t1`.`propertyId` = `PL`.`propertyId`
LEFT JOIN `sa_localitiez` L ON `L`.`id` = `PL`.`localityId`
LEFT JOIN `sb_tblprojectlocality` PROL ON `PROL`.`projectId` = `P`.`id`
LEFT JOIN `sa_localitiez` L2 ON `L2`.`id` = `PROL`.`localityId`
LEFT JOIN `sb_tblfloor` F
ON `F`.`floorName` =`t1`.`floor`
WHERE `t1`.`is_sold` != '1' GROUP BY `t1`.`propertyId`
ORDER BY `t1`.`dateConfirm`
DESC LIMIT 1000
Please provide the EXPLAIN.
Meanwhile, try this:
SELECT ...
FROM (
SELECT propertyId
FROM sb_tblproperty
WHERE `is_sold` = 0
ORDER BY `dateConfirm` DESC
LIMIT 1000
) AS x
JOIN `sb_tblproperty` as t1 ON t1.propertyId = x.propertyId
JOIN `sb_contact` Owner ON `Owner`.`id` = `t1`.`ownerID`
JOIN `tbl_city` C ON `c`.`id` = `t1`.`city`
...
LEFT JOIN `sb_tblfloor` F ON `F`.`floorName` =`t1`.`floor`
ORDER BY `t1`.`dateConfirm` DESC -- yes, again
Together with
INDEX(is_sold, dateConfirm)
How can t1.projectId="" ? Isn't projectId the PRIMARY KEY? (This is one of many reasons for needing the SHOW CREATE TABLE.)
If my suggestion leads to "duplicate" rows (that is, multiple rows with the same propertyId), don't simply add back the GROUP BY propertyId. Instead figure out why, and avoid the need for the GROUP BY. (That is probably the performance issue.)
A likely case is the GROUP_CONCAT. A common workaround is to change from
GROUP_CONCAT( distinct( L.locality)) AS Localities,
...
LEFT JOIN `sa_localitiez` L ON `L`.`id` = `PL`.`localityId`
to
( SELECT GROUP_CONCAT(distinct locality)
FROM sa_localitiez
WHERE id = PL.localityId ) AS Localities
...
# and remove the JOIN

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.

How to subtract a query result from another query result in 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.