Want to short the query - mysql

I have the query, which is giving correct result, but, I am sure there are other way to do so, having same conditions repeated.
Can anybody help me to reduce the complexity of the query.
Query using these mysql parameters:-
SELECT avai.account_visit_account_info_pk AS Account_ID,
mb.NAME AS Client_Name,
mb.fullname AS Client_Full_Name,
avai.account_name AS Account_Name,
mc.NAME AS Asset_City,
Format(( bfd.finance_value ), 'en_IN') AS Reserve_Price,
Format(( bfd.finance_value ) * 10 / 100, 'en_IN') AS EMD_Value,
Ifnull(Concat(CASE
WHEN mpc.parent = 4 THEN 'Residential'
WHEN mpc.parent = 5 THEN 'Commercial'
WHEN mpc.parent = 6 THEN 'Industrial'
WHEN mpc.parent = 7 THEN 'Agricultural'
END, '/', mpc.category_name), mpc.category_name) Asset_Category,
Concat(ud.first_name, ' ', ud.last_name) AS ADM_Name,
Concat(udd.first_name, ' ', udd.last_name) AS MKT_Name,
mcc.NAME AS ADM_City,
ms.NAME AS ADM_State,
mz.NAME AS ADM_Zone,
bec.e_auction_from AS Auction_Date,
bfdd.finance_value AS Sold_Price
FROM account_branch_visit abv
JOIN mst_product_category mpc
ON mpc.mst_product_category_pk = abv.mst_product_category_pk
JOIN mst_bank mb
ON abv.mst_bank_pk = mb.mst_bank_pk
JOIN banking_financial_details bfd
ON abv.account_branch_visit_pk = bfd.account_branch_visit_pk
AND bfd.mst_financial_pk IN ( 33 )
LEFT JOIN banking_financial_details bfdd
ON abv.account_branch_visit_pk = bfdd.account_branch_visit_pk
AND bfd.mst_financial_pk IN ( 38 )
JOIN mst_city mc
ON mc.mst_city_pk = avai.mst_city_pk
JOIN mst_city mcc
ON mcc.mst_city_pk = avai.mst_city_pk
JOIN mst_state ms
ON ms.mst_state_pk = mcc.mst_state_pk
JOIN mst_zone mz
ON mz.mst_zone_pk = ms.mst_zone_pk
JOIN case_allocation ca
ON ca.account_branch_visit_pk = avai.account_branch_visit_pk
AND ca.mst_activity_pk = 21
JOIN case_allocation caa
ON caa.account_branch_visit_pk = avai.account_branch_visit_pk
AND caa.mst_activity_pk = 18
JOIN user_detail ud
ON ud.user_detail_pk = ca.assignedto
JOIN user_detail udd
ON udd.user_detail_pk = caa.assignedto
JOIN banking_event_calender bec
ON bec.account_branch_visit_pk = avai.account_branch_visit_pk
AND ( abv.closed_reasons_pk IS NULL
OR abv.closed_reasons_pk = 16 )
AND abv.isdeleted = '0'
WHERE avai.account_branch_visit_pk = '1301';

I do not know what the exact intent of the query is, so I will provide some technical nuances, without actually understanding your data model or goal. The select clause provides you some columns and you probably need it. So, what I'm looking for are duplicate table joins. Some of them are necessary, some of them are unnecessary.
banking_financial_details
You join and left join this table with different ideas. You use both of them, so I assume this is necessary.
mst_city
This is obviously unnecessarily duplicating:
JOIN mst_city mc
ON mc.mst_city_pk = avai.mst_city_pk
JOIN mst_city mcc
ON mcc.mst_city_pk = avai.mst_city_pk
Remove the second JOIN and ON clauses from the above and replace all usages of mcc to mc in the query.
case_allocation
You join this table twice, but with different ids and you then join the corresponding user_detail to both and both user_detail instances are being used, so this is probably necessary.
user_detail
Since this duplicated join seems to be used in the select, it's probably necessary.
Summary
We have found an unnecessary join that can be removed. Further shortening of the query may be possible, but we would need to know more about your task and database to determine further improvements.

Related

this Query is taking 15 seconds

i added indexes as well but still it is taking 13 sec
I added compound index for all the columns that i've used here
SELECT carrierbil2_.IDENTITY AS col_0_0_,
carrier4_.CARRIER_NAME AS col_1_0_,
carrier4_.IDENTITY AS col_2_0_,
carrier4_.CARRIER_ID AS col_3_0_,
shipmentor0_.EXTERNAL_REFERENCE_ID AS col_4_0_,
invoicedet5_.INVOICE_NUMBER AS col_5_0_,`enter code here`
shipmentca1_.CARRIER_REFERENCE_NUMBER AS col_6_0_,
SUM(shipmentco9_.RATED_COST) AS col_7_0_,
SUM(shipmentco9_.COST) AS col_8_0_,
invoice6_.TOTAL_PAID_AMOUNT AS col_9_0_,
invoice6_.INVOICE_GENERATED_DATE AS col_10_0_,
shipmentor0_.ACTUAL_SHIP_DATE AS col_11_0_,
bolstatus15_.BOL_STATUS_ID AS col_12_0_,
shipmentlo10_.LOCATION_NAME AS col_13_0_,
country11_.COUNTRY_NAME AS col_14_0_,
postal14_.POSTAL_CODE AS col_15_0_,
state12_.STATE_NAME AS col_16_0_,
city13_.CITY_NAME AS col_17_0_,
shipmentlo16_.LOCATION_NAME AS col_18_0_,
country17_.COUNTRY_NAME AS col_19_0_,
postal20_.POSTAL_CODE AS col_20_0_,
state18_.STATE_NAME AS col_21_0_,
city19_.CITY_NAME AS col_22_0_,
shipmentor0_.IDENTITY AS col_23_0_,
shipmentca1_.IDENTITY AS col_24_0_,
shipmentno7_.NOTE AS col_25_0_
FROM
SHIPMENT_ORDER shipmentor0_
INNER JOIN
SHIPMENT_CARRIER shipmentca1_ ON shipmentor0_.SHIPMENT_ORDER_ID = shipmentca1_.SHIPMENT_ORDER_ID
AND (shipmentca1_.IS_DELETED = 0)
LEFT OUTER JOIN
CARRIER_BILL_DETAILS carrierbil2_ ON shipmentca1_.SHIPMENT_CARRIER_ID = carrierbil2_.SHIPMENT_CARRIER_ID
LEFT OUTER JOIN
CARRIER_BILLS carrierbil3_ ON carrierbil2_.CARRIER_BILL_ID = carrierbil3_.CARRIER_BILL_ID
INNER JOIN
CARRIER carrier4_ ON shipmentca1_.CARRIER_ID = carrier4_.CARRIER_ID
LEFT OUTER JOIN
INVOICE_DETAILS invoicedet5_ ON shipmentor0_.SHIPMENT_ORDER_ID = invoicedet5_.SHIPMENT_ORDER_ID
LEFT OUTER JOIN
INVOICE invoice6_ ON invoicedet5_.INVOICE_ID = invoice6_.INVOICE_ID
LEFT OUTER JOIN
SHIPMENT_NOTES shipmentno7_ ON shipmentor0_.SHIPMENT_ORDER_ID = shipmentno7_.SHIPMENT_ORDER_ID
AND (shipmentno7_.NOTE_TYPE = 4)
LEFT OUTER JOIN
SHIPMENT_COST shipmentco8_ ON shipmentor0_.SHIPMENT_ORDER_ID = shipmentco8_.SHIPMENT_ID
LEFT OUTER JOIN
SHIPMENT_COST_DETAILS shipmentco9_ ON shipmentco8_.SHIPMENT_COST_ID = shipmentco9_.SHIPMENT_COST_ID
AND (shipmentco9_.IS_DELETED = 0)
LEFT OUTER JOIN
SHIPMENT_LOCATION shipmentlo10_ ON shipmentor0_.ORIGIN_ID = shipmentlo10_.SHIPMENT_LOCATION_ID
AND (shipmentlo10_.LOCATION_TYPE_ID = 3)
LEFT OUTER JOIN
COUNTRY country11_ ON shipmentlo10_.COUNTRY_ID = country11_.COUNTRY_ID
LEFT OUTER JOIN
STATE state12_ ON shipmentlo10_.STATE_ID = state12_.STATE_ID
LEFT OUTER JOIN
CITY city13_ ON shipmentlo10_.CITY_ID = city13_.CITY_ID
LEFT OUTER JOIN
POSTAL postal14_ ON shipmentlo10_.POSTAL_ID = postal14_.POSTAL_ID
LEFT OUTER JOIN
BOL_STATUS bolstatus15_ ON shipmentor0_.ORDER_STATUS = bolstatus15_.BOL_STATUS_ID
LEFT OUTER JOIN
SHIPMENT_LOCATION shipmentlo16_ ON shipmentor0_.DESTINATION_LOCATION_ID = shipmentlo16_.SHIPMENT_LOCATION_ID
AND (shipmentlo16_.LOCATION_TYPE_ID = 4)
LEFT OUTER JOIN
COUNTRY country17_ ON shipmentlo16_.COUNTRY_ID = country17_.COUNTRY_ID
LEFT OUTER JOIN
STATE state18_ ON shipmentlo16_.STATE_ID = state18_.STATE_ID
LEFT OUTER JOIN
CITY city19_ ON shipmentlo16_.CITY_ID = city19_.CITY_ID
LEFT OUTER JOIN
POSTAL postal20_ ON shipmentlo16_.POSTAL_ID = postal20_.POSTAL_ID
CROSS JOIN
CLIENT client21_
WHERE
shipmentor0_.CLIENT_ID = client21_.CLIENT_ID
AND bolstatus15_.SEQUENCE_ID >= 700
AND (carrierbil3_.IS_APPROVED = 0
OR carrierbil3_.IS_APPROVED IS NULL)
AND (carrierbil3_.IS_DELETED = 0
OR carrierbil3_.IS_DELETED IS NULL)
AND (carrierbil2_.IS_DELETED = 0
OR carrierbil2_.IS_DELETED IS NULL)
AND (shipmentor0_.IS_DELETED = 0
OR shipmentor0_.IS_DELETED IS NULL)
GROUP BY invoice6_.INVOICE_GENERATED_DATE , shipmentca1_.IDENTITY , invoicedet5_.INVOICE_NUMBER , invoice6_.TOTAL_PAID_AMOUNT , shipmentca1_.CARRIER_REFERENCE_NUMBER , carrier4_.CARRIER_ID , CAST(carrier4_.IDENTITY AS SIGNED) , carrier4_.CARRIER_NAME , CAST(carrierbil2_.IDENTITY AS SIGNED) , shipmentor0_.SHIPMENT_ORDER_ID , shipmentno7_.NOTE , shipmentor0_.EXTERNAL_REFERENCE_ID , shipmentlo10_.LOCATION_NAME , country11_.COUNTRY_NAME , postal14_.POSTAL_CODE , state12_.STATE_NAME , city13_.CITY_NAME , shipmentlo16_.LOCATION_NAME , country17_.COUNTRY_NAME , postal20_.POSTAL_CODE , state18_.STATE_NAME , city19_.CITY_NAME , shipmentor0_.IDENTITY
ORDER BY shipmentor0_.SHIPMENT_ORDER_ID DESC;
The indexes are mostly useless because of OR, as in
AND (carrierbil3_.IS_APPROVED = 0
OR carrierbil3_.IS_APPROVED IS NULL)
The simple way to fix that is to pick either 0 or NULL to represent the flag. Then make sure all the data is consistent, and change the WHERE to just check for the one case.
Do you really mean
CROSS JOIN
CLIENT client21_
That is likely to be a performance-killer and generate a huge resultset.
Never mind. You have the ON in WHERE. Please use ON for relations and WHERE for filtering.
WHERE
shipmentor0_.CLIENT_ID = client21_.CLIENT_ID
I see a mixture of LEFT JOIN and JOIN. Check that the LEFT JOINs really need to be LEFT; that is, the 'right' table might have missing data.
To discuss further, please provide EXPLAIN SELECT ....
Eschew over-normalization:
You have 5 tables to describe a location (name, country, postal, state, city). Instead, I recommend a single table with those 5 columns. This, alone, would get rid of 8 JOINs.
CAST(carrier4_.IDENTITY AS SIGNED) -- Can't you fix the datatype to be SIGNED, or allow the value to be UNSIGNED?
But perhaps the main performance-killer is the "explode-implode" syndrone. First, it does a lot of JOINs, building a huge intermediate table, then it collapses that by doing GROUP BY. The remedy is
SELECT ...
FROM ( SELECT SUM(...), SUM(...) FROM ... GROUP BY ... ) AS a
JOIN ((whatever else is needed));
That is, first devise a minimal "derived table" that does the GROUP BY (and/or ORDER BY and/or LIMIT). Then see what else is needed to complete the query (namely all the normalization lookups).
After you have acted on most of my comments, we can discuss whether you have the optimal indexes. (It is premature to do so now.) If so, please start a new Question; it would be too much clutter to add to this one.
First of all, that's a lot of joins. However, the main reason your query is taking a significant time is because you're adding an order by clause. You need to figure out a way to avoid it, or may be come up with a different strategy

How to join a few tables without repeat?

I have a SQL query that left joins a few tables in different ways depending on a conditions.
SELECT
dh_partner.company_name,
dh_partner_abonnement.name,
dh_partner_abonnement.description,
dh_partner_abonnement.price,
dh_partner_abonnement.discount_price,
dh_studio.partner_id,
CONCAT('https://some.url/images/studio/logo/', dh_studio.logo) as logo_url,
CONCAT('https://some.url/studio/', dh_studio.alias) as page_url,
CONCAT('https://some.url/order/abonnement/', dh_studio.alias, '/', dh_partner_abonnement_studios.abonnement_id) as checkout_url
FROM dh_partner_abonnement
LEFT JOIN dh_partner on dh_partner.id = dh_partner_abonnement.partner_id
LEFT JOIN dh_studio on dh_studio.partner_id = dh_partner.id
LEFT JOIN dh_partner_abonnement_studios on dh_partner_abonnement_studios.studio_id = dh_studio.id
WHERE
dh_partner.status = 'active'
and dh_partner.id = dh_studio.partner_id
and dh_partner.city_id = '1'
and dh_partner_abonnement_studios.studio_id = dh_studio.id
and dh_studio.show_status = '1'
The challenge in the following code
CONCAT('https://some.url/ru/order/abonnement/', dh_studio.alias, '/', dh_partner_abonnement_studios.abonnement_id) as checkout_url
LEFT JOIN dh_partner_abonnement_studios on dh_partner_abonnement_studios.studio_id = dh_studio.id
and dh_partner_abonnement_studios.studio_id = dh_studio.id
It repeats to the each dh_partner_abonnement this column dh_partner_abonnement_studios.abonnement_id
I have to connect them correctly. I know that I need to use if, however having no idea how.
Just guessing from the table names:
SELECT
p.company_name,
pa.name,
pa.description,
pa.price,
pa.discount_price,
s.partner_id,
CONCAT('https://some.url/images/studio/logo/', s.logo) as logo_url,
CONCAT('https://some.url/studio/', s.alias) as page_url,
CONCAT('https://some.url/order/abonnement/', s.alias, '/', pa.abonnement_id)
as checkout_url
FROM dh_partner_abonnement pa
JOIN dh_partner_abonnement_studios pas ON pas.partner_id = pa.partner_id
AND pas.abonnement_id = pa.abonnement_id
JOIN dh_studio s ON s.id = pas.studio_id
AND s.show_status = 1
JOIN dh_partner p ON p.id = pa.partner_id
AND p.status = 'active'
AND p.city_id = 1
You haven't joined dh_partner_abonnement and dh_partner_abonnement_studios on the complete key, which should include the abonnement_id.
It also seems a studio has a partner_id to indicate that it belongs to a certain partner. However, in your query you are interested in the abbonement studios, so join the studio on the abbonement's studio_ids.

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

Rails - How to force associations to use alias table name

p = Patient.find(30)
p.patient_problems
The above code generates the following query
SELECT `patient_problem`.* FROM `patient_problem` WHERE `patient_problem`.`patient_id` = 30 AND (`patient_problem`.`record_status_id` = 1)
But is there any way to assign/use alias table_name like
p.patient_problems(:alias=>'p1') # just for Ex.. This code will not work
p.patient_problems(:alias=>'p2') # just for Ex.. This code will not work
So it will generate the following queries
SELECT `p1`.* FROM `patient_problem` AS `p1` WHERE `p1`.`patient_id` = 30 AND (`p1`.`record_status_id` = 1)
SELECT `p2`.* FROM `patient_problem` AS `p2` WHERE `p2`.`patient_id` = 30 AND (`p2`.`record_status_id` = 1)
Additional Info
My problem is when I try to use joins
p.patient_problems(:all,:joins=>joins)
I get this error
ActionView::Template::Error (Mysql2::Error: Not unique table/alias: 'patient_problem': SELECT `patient_problem`.* FROM `patient_problem` LEFT OUTER JOIN party on party.id = patient_problem.patient_id
LEFT OUTER JOIN party_identifier on party.id = party_identifier.party_id
LEFT OUTER JOIN blood_type on blood_type.id = party.blood_type_id
LEFT OUTER JOIN education_level on education_level.id = party.education_level_id
LEFT OUTER JOIN religion on religion.id = party.religion_id
LEFT OUTER JOIN living_arrangement on living_arrangement.id = party.living_arrangement_id
LEFT OUTER JOIN patient_problem patient_problem on patient_problem.patient_id = party.id and patient_problem.record_status_id = 1
left join (select user_type,username,user_id,auditable_id from (select MAX(id) id from audits where audits.auditable_type = 'PatientProblem' and user_type is not null group by auditable_id ) t inner join audits v on v.id=t.id ) entered_by1 on entered_by1.auditable_id = patient_problem.id
left outer join user user1 on entered_by1.user_id = user1.id
left outer join party as party_user1 on party_user1.id = user1.person_id
LEFT OUTER JOIN patient_patient_search patient_patient_search1 on patient_patient_search1.patient_id = party.id
left join search search1 on patient_patient_search1.patient_search_id = search1.id
and patient_patient_search1.patient_search_id = '75' WHERE `patient_problem`.`patient_id` = 45 AND (`patient_problem`.`record_status_id` = 1) AND ( (patient_problem.occurrence_date > '2013-01-01 00:00:00' and patient_problem.occurrence_date < '2013-06-30 23:59:59' and patient_problem.patient_problem_status_id in (5) and patient_problem.code is not null and patient_problem.code in ('10725009') ) and ( patient_patient_search1.patient_search_id in (75.0) ) ))
Ofcourse I could do some string manipulation on the generated joins query and set alias to patient_problem. But I thought setting alias for associations would be more cleaner since the joins query generated are unpredictable(in my scenario)
I am not sure what the variable joins is or how it was constructed. To alias tables in a join build your query like
Rails 3
PatientProblem.joins("as p1 OUTER JOIN patient_problem as p2 on ...")
or
PatientProblem.find(:all, :joins => "as p1 OUTER JOIN patient_problem as p2 ON ...")
you can make singleton methods for that and write the query one time and use may time like
def self.p1
#your active record query here.
end
and call like
PatientProblem.p1
Update
You can simply change the table name in your code:
Patient.table_name="p2"
I'm not sure if this would break anything else though ... so good luck!
Orignal Answer
One solution may be to define a separate model for each type of patient_problem and then do something like this:
class PatientProblem2 < ActiveRecord::Base
self.set_table_name "p2"
...
end
Another solution may be to use the ActiveRecord query interface which will allows for significant query flexibility:
http://guides.rubyonrails.org/active_record_querying.html
Perhaps you can be more specific on the nature problem you are trying to solve.

MySQL - Multirow Sum without Subquery

I currently have this working using a Sub-query, but as the DB grows this will become HUGELY inefficient. I'm wondering if there is a more efficient way to do what I need to do without sub-queries?
I need to have my final output look like so:
Question, Answer, Responses, Charts included in Response Count
Did this work?, N/A, 26, 30
Did this work?, Yes, 4, 30
This is my current query:
SELECT
bq_text,
ba_a,
bq_id,
COUNT(ba_a) AS ba_aC,
(SELECT COUNT(*) FROM board_done_sheet WHERE sd_b_id = bs.bs_id AND sd_sub = 1) AS sd_chartnumC
FROM board_done_sheet AS sh
LEFT JOIN board_done bd
ON (bd.bd_id = sh.sd_bd_id)
LEFT JOIN boardsubs bs
ON (bd.bd_b_id = bs.bs_id)
LEFT JOIN b_q_answers ba
ON (sh.sd_s_id = ba.ba_s_id)
LEFT JOIN bsquestions bq
ON (bq.bq_id = ba.ba_q_id)
LEFT JOIN multiples m
ON (ba.ba_m_id = m.m_id)
LEFT JOIN users u
ON (u.us_id = bd.bd_d_id)
LEFT JOIN profiles p
ON (p.p_u_id = bd.bd_d_id)
LEFT JOIN users rev
ON (rev.us_id = bd.bd_rev)
WHERE sd_sub = '1' AND bq_text <> 'Date' AND bq_id = 380
GROUP BY bs_id, bq_text, ba_a
That works perfectly, the problem is it has to use sub-queries which as time goes by will get less efficient.
I'm just wondering if there is a better more efficient way to do that summed field without it.
Presumably the subquery you're concerned about is the one in your toplevel SELECT.
That is easy to refactor so it won't get repeated.
Just JOIN it to the rest of the table. You'll want this sort of thing:
SELECT
bq_text, ...
COUNT(ba_a) AS ba_aC,
countup.countup AS sd_chartnumC
FROM board_done_sheet AS sh
LEFT JOIN board_done bd
ON (bd.bd_id = sh.sd_bd_id)
...
LEFT JOIN users rev
ON (rev.us_id = bd.bd_rev)
JOIN (
SELECT COUNT(*) AS countup , sd_b_id
FROM board_done_sheet
WHERE sd_sub = 1
GROUP BY sd_b_id
) AS countup ON countup.sd_b_id = bs.bs_id
WHERE sd_sub = '1'
AND bq_text <> 'Date'
AND bq_id = 380
GROUP BY bs_id, bq_text, ba_a
The countup subquery generates a summary table of counts and ids, and then joins it to the other tables.
A JOIN cascade of this complexity may become inefficient for other reasons as your table grows if you don't structure your indexes correctly.