MySQL Query too large, is there a way to opimize? - mysql

Is there any way to optimize this large MySQL Query? I have tried many things, but they all give me results that are not correct, such as duplicates and empty columns.
SELECT quotations.*,
GROUP_CONCAT(DISTINCT CONCAT(groups.group_id, " | ", groups.group_name) SEPARATOR " , ") AS `quotation_groups`,
GROUP_CONCAT(DISTINCT CONCAT(departments.department_id, " | ", departments.department_name, " | ", departments.department_code) SEPARATOR " , ") AS `quotation_departments`,
GROUP_CONCAT(DISTINCT CONCAT(projects.project_id) SEPARATOR " , ") AS `quotation_projects`,
GROUP_CONCAT(DISTINCT CONCAT(machines.machine_id, " | ", machines.machine_name) SEPARATOR " , ") AS `quotation_machines`,
GROUP_CONCAT(DISTINCT CONCAT(parts.part_id, " | ", parts.part_name) SEPARATOR " , ") AS `quotation_parts`,
GROUP_CONCAT(DISTINCT CONCAT(options.option_id, " | ", options.option_name) SEPARATOR " , ") AS `quotation_options`,
GROUP_CONCAT(DISTINCT CONCAT(applications.application_id, " | ", applications.application_nl_title) SEPARATOR " , ") AS `quotation_applications`,
GROUP_CONCAT(DISTINCT CONCAT(actions.action_id, " | ", actions.action_name) SEPARATOR " , ") AS `quotation_actions`,
GROUP_CONCAT(DISTINCT CONCAT(tests.test_id, " | ", tests.test_name) SEPARATOR " , ") AS `quotation_tests`,
GROUP_CONCAT(DISTINCT CONCAT(notes.note_id, " | ", notes.note_name) SEPARATOR " , ") AS `quotation_notes`,
GROUP_CONCAT(DISTINCT CONCAT(companies.company_id, " | ", companies.company_name) SEPARATOR " , ") AS `quotation_companies`,
GROUP_CONCAT(DISTINCT CONCAT(persons.person_id, " | ", persons.person_gender, " | ", persons.person_firstname, " | ", persons.person_middlename, " | ", persons.person_lastname, " | ", persons.person_function) SEPARATOR " , ") AS `quotation_persons`,
GROUP_CONCAT(DISTINCT CONCAT(addresses.address_id, " | ", addresses.address_types, " | ", addresses.address_name, " | ", addresses.address_streetname, " | ", addresses.address_housenumber, " | ", addresses.address_zipcode, " | ", addresses.address_city) SEPARATOR " , ") AS `quotation_addresses`,
GROUP_CONCAT(DISTINCT CONCAT(attachments.attachment_id, " | ", attachments.attachment_name) SEPARATOR " , ") AS `quotation_attachments`
FROM quotations quotations
LEFT JOIN quotations_relations quotation_departments ON (quotation_departments.quotations_relations_child_name="departments" AND quotation_departments.quotations_relations_parent=quotations.quotation_id)
LEFT JOIN quotations_relations quotation_groups ON (quotation_groups.quotations_relations_child_name="groups" AND quotation_groups.quotations_relations_parent=quotations.quotation_id)
LEFT JOIN quotations_relations quotation_projects ON (quotation_projects.quotations_relations_child_name="projects" AND quotation_projects.quotations_relations_parent=quotations.quotation_id)
LEFT JOIN quotations_relations quotation_machines ON (quotation_machines.quotations_relations_child_name="machines" AND quotation_machines.quotations_relations_parent=quotations.quotation_id)
LEFT JOIN quotations_relations quotation_parts ON (quotation_parts.quotations_relations_child_name="parts" AND quotation_parts.quotations_relations_parent=quotations.quotation_id)
LEFT JOIN quotations_relations quotation_options ON (quotation_options.quotations_relations_child_name="options" AND quotation_options.quotations_relations_parent=quotations.quotation_id)
LEFT JOIN quotations_relations quotation_applications ON (quotation_applications.quotations_relations_child_name="applications" AND quotation_applications.quotations_relations_parent=quotations.quotation_id)
LEFT JOIN quotations_relations quotation_actions ON (quotation_actions.quotations_relations_child_name="actions" AND quotation_actions.quotations_relations_parent=quotations.quotation_id)
LEFT JOIN quotations_relations quotation_tests ON (quotation_tests.quotations_relations_child_name="tests" AND quotation_tests.quotations_relations_parent=quotations.quotation_id)
LEFT JOIN quotations_relations quotation_notes ON (quotation_notes.quotations_relations_child_name="notes" AND quotation_notes.quotations_relations_parent=quotations.quotation_id)
LEFT JOIN quotations_relations quotation_companies ON (quotation_companies.quotations_relations_child_name="companies" AND quotation_companies.quotations_relations_parent=quotations.quotation_id)
LEFT JOIN quotations_relations quotation_persons ON (quotation_persons.quotations_relations_child_name="persons" AND quotation_persons.quotations_relations_parent=quotations.quotation_id)
LEFT JOIN quotations_relations quotation_addresses ON (quotation_addresses.quotations_relations_child_name="addresses" AND quotation_addresses.quotations_relations_parent=quotations.quotation_id)
LEFT JOIN quotations_relations quotation_attachments ON (quotation_attachments.quotations_relations_child_name="attachments" AND quotation_attachments.quotations_relations_parent=quotations.quotation_id)
LEFT JOIN groups_relations groups_relations ON (groups_relations.groups_relations_child_name="quotations" AND groups_relations.groups_relations_child_id=quotations.quotation_id)
LEFT JOIN groups groups ON (groups.group_id=groups_relations.groups_relations_parent OR groups.group_id=quotation_groups.quotations_relations_child_id)
LEFT JOIN departments_relations departments_relations ON (departments_relations.departments_relations_child_name="quotations" AND departments_relations.departments_relations_child_id=quotations.quotation_id)
LEFT JOIN departments departments ON (departments.department_id=departments_relations.departments_relations_parent OR departments.department_id=quotation_departments.quotations_relations_child_id)
LEFT JOIN projects_relations projects_relations ON (projects_relations.projects_relations_child_name="quotations" AND projects_relations.projects_relations_child_id=quotations.quotation_id)
LEFT JOIN projects projects ON (projects.project_id=projects_relations.projects_relations_parent OR projects.project_id=quotation_projects.quotations_relations_child_id)
LEFT JOIN machines_relations machines_relations ON (machines_relations.machines_relations_child_name="quotations" AND machines_relations.machines_relations_child_id=quotations.quotation_id)
LEFT JOIN machines machines ON (machines.machine_id=machines_relations.machines_relations_parent OR machines.machine_id=quotation_machines.quotations_relations_child_id)
LEFT JOIN parts_relations parts_relations ON (parts_relations.parts_relations_child_name="quotations" AND parts_relations.parts_relations_child_id=quotations.quotation_id)
LEFT JOIN parts parts ON (parts.part_id=parts_relations.parts_relations_parent OR parts.part_id=quotation_parts.quotations_relations_child_id)
LEFT JOIN options_relations options_relations ON (options_relations.options_relations_child_name="quotations" AND options_relations.options_relations_child_id=quotations.quotation_id)
LEFT JOIN options options ON (options.option_id=options_relations.options_relations_parent OR options.option_id=quotation_options.quotations_relations_child_id)
LEFT JOIN applications_relations applications_relations ON (applications_relations.applications_relations_child_name="quotations" AND applications_relations.applications_relations_child_id=quotations.quotation_id)
LEFT JOIN applications applications ON (applications.application_id=applications_relations.applications_relations_parent OR applications.application_id=quotation_applications.quotations_relations_child_id)
LEFT JOIN actions_relations actions_relations ON (actions_relations.actions_relations_child_name="quotations" AND actions_relations.actions_relations_child_id=quotations.quotation_id)
LEFT JOIN actions actions ON (actions.action_id=actions_relations.actions_relations_parent OR actions.action_id=quotation_actions.quotations_relations_child_id)
LEFT JOIN tests_relations tests_relations ON (tests_relations.tests_relations_child_name="quotations" AND tests_relations.tests_relations_child_id=quotations.quotation_id)
LEFT JOIN tests tests ON (tests.test_id=tests_relations.tests_relations_parent OR tests.test_id=quotation_tests.quotations_relations_child_id)
LEFT JOIN notes_relations notes_relations ON (notes_relations.notes_relations_child_name="quotations" AND notes_relations.notes_relations_child_id=quotations.quotation_id)
LEFT JOIN notes notes ON (notes.note_id=notes_relations.notes_relations_parent OR notes.note_id=quotation_notes.quotations_relations_child_id)
LEFT JOIN companies_relations companies_relations ON (companies_relations.companies_relations_child_name="quotations" AND companies_relations.companies_relations_child_id=quotations.quotation_id)
LEFT JOIN companies companies ON (companies.company_id=companies_relations.companies_relations_parent OR companies.company_id=quotation_companies.quotations_relations_child_id)
LEFT JOIN persons_relations persons_relations ON (persons_relations.persons_relations_child_name="quotations" AND persons_relations.persons_relations_child_id=quotations.quotation_id)
LEFT JOIN persons persons ON (persons.person_id=persons_relations.persons_relations_parent OR persons.person_id=quotation_persons.quotations_relations_child_id)
LEFT JOIN addresses_relations addresses_relations ON (addresses_relations.addresses_relations_child_name="quotations" AND addresses_relations.addresses_relations_child_id=quotations.quotation_id)
LEFT JOIN addresses addresses ON (addresses.address_id=addresses_relations.addresses_relations_parent OR addresses.address_id=quotation_addresses.quotations_relations_child_id)
LEFT JOIN attachments_relations attachments_relations ON (attachments_relations.attachments_relations_child_name="quotations" AND attachments_relations.attachments_relations_child_id=quotations.quotation_id)
LEFT JOIN attachments attachments ON (attachments.attachment_id=attachments_relations.attachments_relations_parent OR attachments.attachment_id=quotation_attachments.quotations_relations_child_id)
GROUP BY quotations.quotation_id ORDER BY quotations.quotation_updated DESC
As you can see, i need to get all details from every table that have a relation with eachother.
I noticed, that, after a while, the more relations there are, the slower the query is, for example, i have this quotation with 103 relations, it takes up to 34seconds to gather all data.

My first suggestion would be to do a single join with conditional aggregation. You will probably not need the DISTINCT in GROUP_CONCAT() any more. Here is an example for departments:
SELECT q.*,
GROUP_CONCAT(CASE WHEN qr.quotations_relations_child_name = 'departments' THEN qr.department_id, ' | ', qr.department_name END)
FROM quotations q LEFT JOIN
quotations_relations qr
ON qr.quotations_relations_parent = q.quotation_id
GROUP BY q.quotation_id
ORDER BY q.quotation_updated DESC ;

For a start, you could use only one join for the quotations:
LEFT JOIN quotations_relations ON quotations_relations_parent=quotations.quotation_id
and do the relation check on the individual rows:
e.g.
LEFT JOIN groups groups ON
(
groups.group_id=groups_relations.groups_relations_parent OR
(groups.group_id=quotations_relations.quotations_relations_child_id AND quotations_relations_child_name="groups")
)

Related

MySQL - Left and Self Join in single query

As the title states I am trying to Left Join information from table B, but then also show matching information in table A, thats not associated in table B. Below is my query but it's currently only returning the inner join.
SELECT
concat(u.firstname, ' ', u.lastname) AS clientName,
u.email AS clientEmail,
u.created_at AS signedUp,
u.refferedby AS referredBy,
concat(t.firstname, ' ', t.lastname) AS trainerWho,
t.email AS trainerWhoEmail,
concat(usr.firstname, ' ', usr.lastname) AS clientWho,
usr.email as clientWhoEmail
FROM users u
LEFT JOIN trainers t ON u.externalid = t.hashId
INNER JOIN users usr ON u.externalid = usr.hashId
WHERE u.refferedby IS NOT NULL
AND DATE(u.created_at) >= CURDATE() -7
ORDER BY(u.created_at);

Combining 3 querys on SQL

I have a table with both, Products and Sevices. And I store the products brands, product names and services names on separate tables.
I get the list of Services with this Query:
SELECT maeinvs.idInv, CONCAT(services.Service, " ", maeinvs.Detail) AS Name
FROM maeinvs
INNER JOIN services
ON services.idService = maeinvs.idService
And the list of Products with this one:
SELECT maeinvs.idInv, CONCAT(brands.Brand, " ", products.Product, " ", maeinvs.Detail) AS Name
FROM maeinvs
INNER JOIN products
ON products.idProduct = maeinvs.idProduct
INNER JOIN brands
ON brands.idBrand = maeinvs.idBrand
I need to get a Query like this, but instead of the idInv field I need the actual Name of the Product or Service. Any ideas?
SELECT idInv, Desc, Qnty, Price
FROM invoicedetails
WHERE idInvoice = $id
Thanks.
SELECT maeinvs.idInv, CONCAT(services.Service, " ", maeinvs.Detail) AS Name,
"" AS Desc, 0 AS Qnty, 0 AS Price
FROM maeinvs
INNER JOIN services
ON services.idService = maeinvs.idService
UNION
SELECT maeinvs.idInv, CONCAT(brands.Brand, " ", products.Product, " ", maeinvs.Detail) AS Name,
"" AS Desc, 0 AS Qnty, 0 AS Price
FROM maeinvs
INNER JOIN products
ON products.idProduct = maeinvs.idProduct
INNER JOIN brands
ON brands.idBrand = maeinvs.idBrand
UNION
SELECT idInv,
"" AS Name,
Desc, Qnty, Price
FROM invoicedetails
WHERE idInvoice = $id
I've written what I've changed on next line
As the columns match each other, UNION will work.
I still don't know how to do it on a single query (I just know the basics; an Alias?) but solved it doing a VIEW and then a JOIN with my invoicedetails table.
VIEW:
SELECT maeinvs.idInv, CONCAT(services.Service, " ", maeinvs.Detail) AS Name
FROM maeinvs
INNER JOIN services
ON services.idService = maeinvs.idService
UNION
SELECT maeinvs.idInv, CONCAT(brands.Brand, " ", products.Product, " ", maeinvs.Detail) AS Name
FROM maeinvs
INNER JOIN products
ON products.idProduct = maeinvs.idProduct
INNER JOIN brands
ON brands.idBrand = maeinvs.idBrand
QUERY:
SELECT viewnames.Name, invoicedetails.Desc, invoicedetails.Qnty, invoicedetails.Price
FROM invoicedetails
INNER JOIN viewnames ON viewnames.idInv = invoicedetails.idInv
WHERE invoicedetails = $id

My sql search syntax implementation

How can I implement search function:
where sub_menu_name like '%".$kws."%'
into my working one:
SELECT DISTINCT p.id, p.sub_menu_id, p.sub_menu_name, m.image_id, i.file_url, m.default_menu_id, p.restaurant_id, p.status, p.sub_menu_price
FROM sub_sub_menu AS p
INNER JOIN menu AS m ON m.default_menu_id = p.sub_menu_id
OR m.id = p.sub_menu_id
INNER JOIN icon AS i ON i.id = m.image_id
WHERE p.restaurant_id = '" . (int) $_SESSION['uid'] . "' "
Thanks for any help!
SELECT DISTINCT p.id, p.sub_menu_id, p.sub_menu_name, m.image_id, i.file_url, m.default_menu_id, p.restaurant_id, p.status, p.sub_menu_price
FROM sub_sub_menu AS p
INNER JOIN menu AS m ON m.default_menu_id = p.sub_menu_id
OR m.id = p.sub_menu_id
INNER JOIN icon AS i ON i.id = m.image_id
WHERE p.restaurant_id = '" . (int) $_SESSION['uid'] . "'
AND sub_menu_name LIKE '%".$kws."%'
I think this is what you want.
But I wonder why you have ". and ." before and after $kws. It's meant for concatenation so it won't work in SQL. If you want to check for $kws IN a value, the % % are enough.

Multiple Count() in Database

I'm making a survey-applican with winforms and VB. This is the SQL I got so far to show statistics:
SELECT
tblAlt.altText,
Count(tblAnswers.answerID)
FROM tblAlt
LEFT JOIN tblAnswers ON (tblAlt.altId = tblAnswers.altID)
WHERE tblAlt.questionID = " & CInt(questionID) & "
GROUP BY tblAlt.altText;
This returns each alternatives for a question, and how many answered them. Is there a way I can count how many answered in total with the same SQL-query?
Tables involved are:
_______________ _______________ ___________ _______________
|_tblUsers____| |_tblAnswers___| |_tblAlt__| |_tblQuestion_|
| userID | | answerAltID | | altID | | questID |
| username | | userID | | altText | | questText |
|_____________| |______________| |_questID_| |_____________|
Any help would be appreciated!
This is what I used in the end:
SELECT
tblAlt.altText,
Count(tblAnswers.answerID),
(SELECT COUNT(answerID) FROM tblAnswers, tblAlt
WHERE tblAnswers.answerAltID = tblAlt.altID
AND tblAlt.questID = " & CInt(questionID) & ") as total_count
FROM tblAlt
LEFT JOIN tblAnswers ON (tblAlt.altId = tblAnswers.altID)
WHERE tblAlt.questID = " & CInt(questionID) & "
GROUP BY tblAlt.altText;
Use ROLLUP:
SELECT
tblAlt.altText,
Count(tblAnswers.answerID)
FROM tblAlt
LEFT JOIN tblAnswers ON (tblAlt.altId = tblAnswers.altID)
WHERE tblAlt.questionID = " & CInt(questionID) & "
GROUP BY tblAlt.altText WITH ROLLUP;
If you want one-time computation(to make query efficient), use CROSS JOIN. Don't worry, this CROSS JOIN won't yield cartesian product, it's only one row. This might be faster than subquery approach:
SELECT
tblAlt.altText,
Count(tblAnswers.answerID), x.total_count
FROM tblAlt
cross join (SELECT COUNT(answerID) as total_count FROM tblAnswers) as x
LEFT JOIN tblAnswers ON (tblAlt.altId = tblAnswers.altID)
WHERE tblAlt.questionID = " & CInt(questionID) & "
GROUP BY tblAlt.altText;
Or use MySqlism, might be faster:
SELECT
tblAlt.altText,
Count(tblAnswers.answerID), #total_count as total_count
FROM tblAlt
cross join (SELECT #total_count := COUNT(answerID) FROM tblAnswers) as x
LEFT JOIN tblAnswers ON (tblAlt.altId = tblAnswers.altID)
WHERE tblAlt.questionID = " & CInt(questionID) & "
GROUP BY tblAlt.altText;
Or you can use multi-statements. Note, SET statements doesn't appear on ADO.NET's DataReader or DataTable. ADO.NET can still get the results from your actual query. This has a certainty to be faster among all approaches:
SET #total_count := (SELECT COUNT(answerID) FROM tblAnswers);
SELECT
tblAlt.altText,
Count(tblAnswers.answerID), #total_count as total_count
FROM tblAlt
LEFT JOIN tblAnswers ON (tblAlt.altId = tblAnswers.altID)
WHERE tblAlt.questionID = " & CInt(questionID) & "
GROUP BY tblAlt.altText;
you can use an subquery to do this, something like:
SELECT
tblAlt.altText,
Count(tblAnswers.answerID),
(SELECT COUNT(answerID) FROM tblAnswers) as total_count
FROM tblAlt
LEFT JOIN tblAnswers ON (tblAlt.altId = tblAnswers.altID)
WHERE tblAlt.questionID = " & CInt(questionID) & "
GROUP BY tblAlt.altText;
Some Resources:
http://beginner-sql-tutorial.com/sql-subquery.htm
http://www.1keydata.com/sql/sql-subquery.html

MySQL COUNT syntax in bigger query

I'm trying to create a query that will return all the jobs published by a specific company, and a count of the total people who applied to this job. the first part works fine - I get all the jobs and everything I need:
$query = "SELECT *,j.job_id as jid, c.name as city_name ".
"FROM jobs j JOIN areas a ON a.area_id = j.job_area ".
"JOIN positions p ON p.position_id = j.job_position ".
"JOIN fields f ON f.id = j.job_field ".
"JOIN cities c ON j.job_city = c.id ".
"JOIN jobTypes jt ON j.job_type = jt.job_id " .
"JOIN companies comp ON j.job_company = comp.company_id ".
"LEFT JOIN jobApplications ja ON ".
"ja.user_id = '".$_SESSION['user_id']."' AND ".
"j.job_id = ja.job_id WHERE j.job_company='$company_id'";
The thing is, that I want to add each result row the number of applicants for the job from the jobApplications table... I tried to add a COUNT column to the query, which works great by itself:
SELECT COUNT(*) FROM jobApplications ja WHERE ja.job_id=j.job_id
when added to the first big query, I didn't manage to make this work even on the syntax level, so i'm not sure if it works at all...
I tried to add the last query to the select area of the main query, but I always get a syntax error right after the 'ja.job_id=j.job_id' in the end of the count query...
Is this even possible ?
I hope the question is clear, I know there are many tables included here...
Thanks for the time and help!
i dont know your PK of jobApplications, but this might work.
$query = "SELECT *,j.job_id as jid, c.name as city_name, COUNT(ja.<primary key>) ".
"FROM jobs j JOIN areas a ON a.area_id = j.job_area ".
"JOIN positions p ON p.position_id = j.job_position ".
"JOIN fields f ON f.id = j.job_field ".
"JOIN cities c ON j.job_city = c.id ".
"JOIN jobTypes jt ON j.job_type = jt.job_id " .
"JOIN companies comp ON j.job_company = comp.company_id ".
"LEFT JOIN jobApplications ja ON ".
"ja.user_id = '".$_SESSION['user_id']."' AND ".
"j.job_id = ja.job_id WHERE j.job_company='$company_id' ".
"GROUP By jid";
You have to use GROUP
SELECT *,j.job_id as jid, c.name as city_name, COUNT(jobApplications.*)
FROM jobs j JOIN areas a ON a.area_id = j.job_area
JOIN positions p ON p.position_id = j.job_position
JOIN fields f ON f.id = j.job_field
JOIN cities c ON j.job_city = c.id
JOIN jobTypes jt ON j.job_type = jt.job_id
JOIN companies comp ON j.job_company = comp.company_id
LEFT JOIN jobApplications ja ON
ja.user_id = '".$_SESSION['user_id']."' AND
j.job_id = ja.job_id WHERE j.job_company='$company_id'
GROUP BY jid
Hope it helps :)
Try it like this:
$query = "SELECT (SELECT COUNT(ja2.job_id) FROM jobApplications ja2 WHERE ja2.job_id=j.job_id group by j.job_id), *,j.job_id as jid, c.name as city_name FROM jobs j JOIN areas a ON a.area_id = j.job_area" .
" JOIN positions p ON p.position_id = j.job_position JOIN fields f ON f.id = j.job_field "
." JOIN cities c ON j.job_city = c.id JOIN jobTypes jt ON j.job_type = jt.job_id " .
"JOIN companies comp ON j.job_company = comp.company_id LEFT JOIN jobApplications ja ON ja.user_id = '".$_SESSION['user_id']."' AND j.job_id = ja.job_id WHERE j.job_company='$company_id'";