Mysql Subquery Work Slowly - mysql

I use view has subquery and concat in mysql. Normally, query works rapidly, but if query has subquery works very slowly.
This code is running quickly (approximate 1 seconds)
CREATE OR REPLACE VIEW ilceler AS (
SELECT I.id, I.modulid, I.id as icerikidsi,
MAX(IF(D.alanid=2,D.textkisa,NULL)) AS ilceadi,
MAX(IF(D.alanid=2,D.id,NULL)) AS ilceadi_i,
I.seo_description,
I.seo_h1,
I.seo_h2,
I.seo_h3,
I.seo_h4,
I.seo_imgalt,
I.seo_imgtitle,
I.seo_keywords,
I.seo_pagetitle,
I.seo_url,
I.seo_urltitle
FROM datalar as D LEFT JOIN icerikler as I ON D.icerikid=I.id WHERE D.modulid='3' GROUP BY D.icerikid ORDER BY sehiradi asc )
But this code is working very very slowly (approximate 20 seconds)
CREATE OR REPLACE VIEW ilceler AS (
SELECT I.id, I.modulid, I.id as icerikidsi,
MAX(IF(D.alanid=2,D.textkisa,NULL)) AS ilceadi,
MAX(IF(D.alanid=2,D.id,NULL)) AS ilceadi_i,
( SELECT CONVERT ( GROUP_CONCAT(D2.id SEPARATOR ' ₋ ' ) USING UTF8 )FROM datalar as D1
LEFT JOIN datalar as D2 ON D1.iliskialanid=D2.id WHERE D1.modulid='3' AND D1.alanid='3' AND D1.icerikid=icerikidsi ) as sehiradi_a ,
( SELECT GROUP_CONCAT(iliskiid SEPARATOR ' ₋ ') FROM datalar WHERE alanid='3' AND modulid='3' AND icerikid=icerikidsi ) as sehiradi_i,
( SELECT GROUP_CONCAT(D2.textkisa SEPARATOR ' ₋ ' ) FROM datalar as D1 LEFT JOIN datalar as D2 ON D1.iliskialanid=D2.id
WHERE D1.modulid='3' AND D1.alanid='3' AND D1.icerikid=icerikidsi ) as sehiradi ,
I.seo_description,
I.seo_h1,
I.seo_h2,
I.seo_h3,
I.seo_h4,
I.seo_imgalt,
I.seo_imgtitle,
I.seo_keywords,
I.seo_pagetitle,
I.seo_url,
I.seo_urltitle
FROM datalar as D LEFT JOIN icerikler as I ON D.icerikid=I.id WHERE D.modulid='3' GROUP BY D.icerikid ORDER BY sehiradi asc )
Why? Where do I make mistake?
I am waiting for your help.

Your sub queries rely on the values of the select, hence each of those 3 sub queries needs to be performed for each returned row. With a small number of rows this isn't an issue but with lots of rows this can rapidly add up.
Normal solution is to join against the sub query (hence it is done once for all rows and you just join the results).
For example:-
SELECT I.id,
I.modulid,
I.id as icerikidsi,
MAX(IF(D.alanid=2,D.textkisa,NULL)) AS ilceadi,
MAX(IF(D.alanid=2,D.id,NULL)) AS ilceadi_i,
sub1.sehiradi_a ,
sub2.sehiradi_i,
sub1.sehiradi ,
I.seo_description,
I.seo_h1,
I.seo_h2,
I.seo_h3,
I.seo_h4,
I.seo_imgalt,
I.seo_imgtitle,
I.seo_keywords,
I.seo_pagetitle,
I.seo_url,
I.seo_urltitle
FROM datalar as D
LEFT JOIN icerikler as I ON D.icerikid=I.id
LEFT OUTER JOIN
(
SELECT D1.icerikid, CONVERT ( GROUP_CONCAT(D2.id SEPARATOR ' ₋ ' ) USING UTF8 ) AS sehiradi_a, GROUP_CONCAT(D2.textkisa SEPARATOR ' ₋ ' ) AS sehiradi
FROM datalar as D1
LEFT JOIN datalar as D2 ON D1.iliskialanid=D2.id
WHERE D1.modulid='3'
AND D1.alanid='3'
GROUP BY D1.icerikid
) sub1
ON sub1.icerikid = I.id
LEFT OUTER JOIN
(
SELECT icerikid, GROUP_CONCAT(iliskiid SEPARATOR ' ₋ ') AS sehiradi_i
FROM datalar
WHERE alanid='3'
AND modulid='3'
GROUP BY icerikid
) sub2
ON sub2.icerikid = I.id
WHERE D.modulid='3'
GROUP BY D.icerikid
ORDER BY sehiradi asc
Or depending on your actual database design you might be able to simplify it to
SELECT I.id,
I.modulid,
I.id as icerikidsi,
MAX(IF(D.alanid=2,D.textkisa,NULL)) AS ilceadi,
MAX(IF(D.alanid=2,D.id,NULL)) AS ilceadi_i,
sub1.sehiradi_a ,
sub1.sehiradi_i,
sub1.sehiradi ,
I.seo_description,
I.seo_h1,
I.seo_h2,
I.seo_h3,
I.seo_h4,
I.seo_imgalt,
I.seo_imgtitle,
I.seo_keywords,
I.seo_pagetitle,
I.seo_url,
I.seo_urltitle
FROM datalar as D
LEFT JOIN icerikler as I ON D.icerikid=I.id
LEFT OUTER JOIN
(
SELECT D1.icerikid,
CONVERT ( GROUP_CONCAT(D2.id SEPARATOR ' ₋ ' ) USING UTF8 ) AS sehiradi_a,
GROUP_CONCAT(D2.textkisa SEPARATOR ' ₋ ' ) AS sehiradi,
GROUP_CONCAT(DISTINCT D1.iliskiid SEPARATOR ' ₋ ') AS sehiradi_i
FROM datalar as D1
LEFT JOIN datalar as D2 ON D1.iliskialanid=D2.id
WHERE D1.modulid='3'
AND D1.alanid='3'
GROUP BY D1.icerikid
) sub1
ON sub1.icerikid = I.id
WHERE D.modulid='3'
GROUP BY D.icerikid
ORDER BY sehiradi asc
However there is a minor issue here. In MySQL a view cannot contain a FROM that takes data from a sub query. As such to use this syntax in your view you would need to split the sub queries off into their own views. Then you could join against the view rather than the sub query.

Related

Slow MySQL Query When Run As A Procedure

If I run this query directly in PHPMyAdmin, it returns 13420 rows in 0.2091 second, but if I run the exact same query as a stored procedure, it returns the same amount of row but it takes forever and sometimes the SQL server returns an out of memory exception.
I'm at a total loss - any advice would be welcome, because I can't work out why this slows everything down?!
SELECT
el.UID as LUID,
se.UID as DUID,
el.event_title,
el.event_synopsis,
se.behind_the_scenes,
se.sub_event_title,
se.event_eventDateAndTime,
se.event_eventDateAndTimeEnd,
el.event_confirmed,
el.event_active,
(
SELECT GROUP_CONCAT(sp2.color SEPARATOR ',')
FROM setup__spaces sp2
LEFT JOIN events__assigned_spaces eas2 ON ( eas2.space_id = sp2.UID )
LEFT JOIN events__events_list el2 ON (el2.UID = eas2.event_id)
WHERE el2.UID = el.UID
) as spaceColors,
(
SELECT GROUP_CONCAT(sp2.name SEPARATOR ', ')
FROM setup__spaces sp2
LEFT JOIN events__assigned_spaces eas2 ON ( eas2.space_id = sp2.UID )
LEFT JOIN events__events_list el2 ON (el2.UID = eas2.event_id)
WHERE el2.UID = el.UID
) as spaceNames,
(
SELECT GROUP_CONCAT(sp2.UID SEPARATOR ',')
FROM setup__spaces sp2
LEFT JOIN events__assigned_spaces eas2 ON ( eas2.space_id = sp2.UID )
LEFT JOIN events__events_list el2 ON (el2.UID = eas2.event_id)
WHERE el2.UID = el.UID
) as spaceIds,
(
SELECT GROUP_CONCAT(t.UID SEPARATOR ',')
FROM setup__tags t
LEFT JOIN events__assigned_tags eat ON ( eat.tag_id = t.UID )
LEFT JOIN events__events_list el2 ON (el2.UID = eat.event_id)
WHERE el2.UID = el.UID
) as tagIds,
(
SELECT GROUP_CONCAT(t.tag_name SEPARATOR ', ')
FROM setup__tags t
LEFT JOIN events__assigned_tags eat ON ( eat.tag_id = t.UID )
LEFT JOIN events__events_list el2 ON (el2.UID = eat.event_id)
WHERE el2.UID = el.UID
) as tagNames
FROM events__events_list el
INNER JOIN events__sub_events se ON (el.UID = se.event_masterEvent)
WHERE ((el.event_active='1') OR (el.event_active='0' AND el.event_confirmed = '1'))
AND el.company_uid = sp_company_uid
With thanks to #Akina for pointing me in the right direction, I found help from the following places:
stackoverflow.com - Selecting multiple columns/fields in MySQL subquery
geeksengine.com - How to use subquery in JOIN operation in MySQL
Here's the revised code that's now lightning fast!
SELECT
el.UID as LUID,
se.UID as DUID,
el.event_title,
el.event_synopsis,
se.behind_the_scenes,
se.sub_event_title,
se.event_eventDateAndTime,
se.event_eventDateAndTimeEnd,
el.event_confirmed,
el.event_active,
tags.names as tagNames,
tags.ids as tagIds,
spaces.names as spaceNames,
spaces.colors as spaceColors,
spaces.ids as spaceIds
FROM events__events_list el
INNER JOIN events__sub_events se ON (el.UID = se.event_masterEvent)
LEFT JOIN (
SELECT
el3.UID as el2uid,
GROUP_CONCAT(s.name SEPARATOR ', ') as names,
GROUP_CONCAT(s.color SEPARATOR ',') as colors,
GROUP_CONCAT(s.UID SEPARATOR ',') as ids
FROM setup__spaces as s
LEFT JOIN events__assigned_spaces eas ON ( eas.space_id = s.UID )
LEFT JOIN events__events_list el3 ON ( el3.UID = eas.event_id )
GROUP BY el3.UID
) as spaces on spaces.el2uid = el.UID
LEFT JOIN (
SELECT
el2.UID as el2uid,
GROUP_CONCAT(t.tag_name SEPARATOR ', ') as names,
GROUP_CONCAT(t.UID SEPARATOR ',') as ids
FROM setup__tags as t
LEFT JOIN events__assigned_tags eat ON ( eat.tag_id = t.UID )
LEFT JOIN events__events_list el2 ON ( el2.UID = eat.event_id )
GROUP BY el2.UID
) as tags on tags.el2uid = el.UID
WHERE ((el.event_active='1') OR (el.event_active='0' AND el.event_confirmed = '1'))
AND el.company_uid = sp_company_uid

sql string can't get right

I'm trying to get some data from my db.
It kinda looks like this
GROUPS
groups_id, groups_name, groups_description, groups_active, groups_hash, groups_entry_date, user_id, groups_email, groups_sms
CUSTOMERS_GROUPS
customers_hash, groups_hash
CUSTOMERS
customers_id, customers_first_name, customers_surname, customers_telephone, customers_email, customers_telephone_active, customers_email_active, client_type, customers_hash, customers_entry_date
I want customers.groups_hash and groups.groups_name in a concat form. Here is my attempt ...
SELECT * , GROUP_CONCAT( DISTINCT customers_groups.groups_hash
SEPARATOR '/' ) , GROUP_CONCAT( groups.groups_name
SEPARATOR '/' )
FROM customers
INNER JOIN customers_groups ON ( customers.customers_hash = customers_groups.customers_hash )
LEFT JOIN groups ON ( customers_groups.customers_hash = groups.groups_hash )
WHERE groups.groups_active ='1' GROUP BY customers.customers_entry_date
but it gives me back a zero set ...
The problem is your where clause. It must be part of the on clause:
SELECT * , GROUP_CONCAT( DISTINCT customers_groups.groups_hash
SEPARATOR '/' ) , GROUP_CONCAT( groups.groups_name
SEPARATOR '/' )
FROM customers
INNER JOIN customers_groups ON ( customers.customers_hash = customers_groups.customers_hash )
LEFT JOIN groups ON ( customers_groups.customers_hash = groups.groups_hash ) AND groups.groups_active ='1'
GROUP BY customers.customers_entry_date
The problem is here:
LEFT JOIN groups ON ( customers_groups.customers_hash = groups.groups_hash )
which should probably be
LEFT JOIN groups ON ( customers_groups.groups_hash = groups.groups_hash )
(While it remains unclear what the hashes actually represent and why there is no bridge table linking the tables' IDs instead. I've asked that question in the comment section to your request.)

how to use select sub query in other query MySQL

I am writing a mysql select sub query, that is working fine, it returns 2 column is there way to select only 1 column.
My query is
SELECT sum(fl.qunt) as qunt,(
SELECT GROUP_CONCAT( xp.id
SEPARATOR ',' )
FROM prdt AS xp
LEFT JOIN prdt_fac AS pf ON pf.fk_product_children = xp.rowid
WHERE pf.prdt_fat = p.id
AND pf.prdt_ch = 6953
GROUP BY pf.prdt_fat
LIMIT 0 , 1
) AS prdt_chd
FROM fac_log AS fl
LEFT JOIN fac AS f ON fl.fac = f.id
LEFT JOIN prdt AS p ON f.prdt = p.id
GROUP BY prod_child
ORDER BY fl.tms DESC
LIMIT 0 , 1
This return two column qunt and prdt_ch.
But i want only column in result qunt.
Is there any way, becuase inner select query is must be used to get correct result.
Main purpose of this query is that i have to use this query as sub query in an other query, in this condition it throws error "operand should contain 1 column"
Thanks in advance
just select qunt using your select query as a table (t)
select qunt from (
SELECT sum(fl.qunt) as qunt,(
SELECT GROUP_CONCAT( xp.id
SEPARATOR ',' )
FROM prdt AS xp
LEFT JOIN prdt_fac AS pf ON pf.fk_product_children = xp.rowid
WHERE pf.prdt_fat = p.id
AND pf.prdt_ch = 6953
GROUP BY pf.prdt_fat
LIMIT 0 , 1
) AS prdt_chd
FROM fac_log AS fl
LEFT JOIN fac AS f ON fl.fac = f.id
LEFT JOIN prdt AS p ON f.prdt = p.id
GROUP BY prod_child
ORDER BY fl.tms DESC
LIMIT 0 , 1 ) t

How to get all records from one table and irrespective of where clause

Below is my Query, when I am putting where clause, my recordset get reduced. I can understand why it reducing,
But I am looking for all records from teacher_profiles table (31 records) and then corresponding details if there is any else blank.
Can any one suggest ? Using mySQL
SELECT
CONCAT(a.teacherFirstName , ' ', COALESCE(a.teacherMiddleName, ''), ' ', a.teacherLastName ) as teacherName ,
COALESCE(GROUP_CONCAT(DISTINCT c.subjectLongName SEPARATOR ', ') , '') AS subjects ,
COALESCE(GROUP_CONCAT(DISTINCT f.classStd SEPARATOR ', ') , '') AS classes ,
FROM
teacher_profiles a **<--- this table has 31 records. I need all these 31** Record in recordset
LEFT JOIN subjectteacherallocation b ON a.teacherId = b.teacherId
LEFT JOIN subject_master c ON b.subjectId = c.subjectId
LEFT JOIN timetabledistribution d ON a.teacherId = d.teacherId
LEFT JOIN TimeTableClassSection e ON d.TimeTableClassSectionId = d.TimeTableClassSectionId
LEFT JOIN class_master f ON f.classId = e.classId
WHERE b.academicYear='2015' <--- condition reducing record
GROUP BY a.teacherId

MYSQL group_concat with and IF

Have a date field that I am getting out of my DB with the following;
PS Here is more of the query using a join to get the dates from the date table.
SELECT event,event_name,
GROUP_CONCAT(DATE_FORMAT(ed.date,'%b %e') ORDER BY ed.date SEPARATOR ',') as date2
FROM events ev
LEFT JOIN event_dates ed ON ev.eid=ed.eid
WHERE ev.yr='2013'
GROUP BY ev.eid
This produces this list of dates that takes up way to much space.
May 16,May 23,May 30,Jun 6,Jun 20
I want it to look like
May 16,23,30,Jun 6,20
Here is the query I tried. but it doesn't work because the sub-query doesn't seem to know the event id. guessing i might need to convert it to a join??
SELECT DISTINCT ev.event_id,
GROUP_CONCAT(DISTINCT DATE_FORMAT(race_date,'%a') ORDER BY race_date
SEPARATOR ', ') as date1,
(SELECT GROUP_CONCAT(dm) FROM
(SELECT CONCAT(
MONTHNAME(race_date),
' ',
GROUP_CONCAT(DAY(race_date) ORDER BY race_date)
) as dm
FROM event_dates ed1 WHERE ed1.event_id=ev.event_id
GROUP BY MONTH(race_date))as t) as date2
FROM events ev
JOIN event_dates ed ON ev.event_id = ed.event_id AND ev.race_year = ed.race_year
GROUP BY event_id
SELECT GROUP_CONCAT(d) FROM (
SELECT CONCAT(
MONTHNAME(date),
' ',
GROUP_CONCAT(DAY(date) ORDER BY date)
) AS d
FROM my_table
GROUP BY MONTH(date)
) t