MySQL if condition then left join - mysql

I have a working Select at the bottom of the page. As you can see, it has 53 lines and, in my opinion, this is too much. I have been told me that there is an 'if' condition available in MySQL, but I have not able to make it work. The working Select unions 4 selects, because in each select, I need to join another table. Is it possible to join tables according to their content?
SELECT *
FROM (
SELECT m.`identificator` , ml.id AS link_id, ml.parent, ml.type,
ml.destination, ml.disabled, ml.order, mld.`name` AS link_name,
mld.`alt` , mld.`title` , cpd.`slug`
FROM `wf_menu` m
LEFT JOIN `wf_menu_link` ml ON m.`id` = ml.`menu_id`
LEFT JOIN `wf_menu_link_desc` mld ON ml.`id` = mld.`link_id`
LEFT JOIN `wf_cms_post_desc` cpd ON ml.destination = cpd.post_id
WHERE mld.`lang_id` =1
AND mld.`lang_id` = cpd.`lang_id`
AND (ml.`type` = 'page'
OR ml.`type` = 'article')
UNION
SELECT m.`identificator` , ml.id AS link_id, ml.parent, ml.type,
ml.destination, ml.disabled, ml.order, mld.`name` AS link_name,
mld.`alt` , mld.`title` , cpd.`slug`
FROM `wf_menu` m
LEFT JOIN `wf_menu_link` ml ON m.`id` = ml.`menu_id`
LEFT JOIN `wf_menu_link_desc` mld ON ml.`id` = mld.`link_id`
LEFT JOIN `wf_cms_category_desc` cpd ON ml.destination = cpd.category_id
WHERE mld.`lang_id` =1
AND mld.`lang_id` = cpd.`lang_id`
AND ml.`type` = 'cmscat'
UNION
SELECT m.`identificator` , ml.id AS link_id, ml.parent, ml.type,
ml.destination, ml.disabled, ml.order, mld.`name` AS link_name,
mld.`alt` , mld.`title` , spd.`slug`
FROM `wf_menu` m
LEFT JOIN `wf_menu_link` ml ON m.`id` = ml.`menu_id`
LEFT JOIN `wf_menu_link_desc` mld ON ml.`id` = mld.`link_id`
LEFT JOIN `wf_shop_category_desc` spd ON ml.destination = spd.category_id
WHERE mld.`lang_id` =1
AND mld.`lang_id` = spd.`lang_id`
AND ml.`type` = 'shopcat'
UNION
SELECT m.`identificator` , ml.id AS link_id, ml.parent, ml.type,
ml.destination, ml.disabled, ml.order, mld.`name` AS link_name,
mld.`alt` , mld.`title` , 'link' as slug
FROM `wf_menu` m
LEFT JOIN `wf_menu_link` ml ON m.`id` = ml.`menu_id`
LEFT JOIN `wf_menu_link_desc` mld ON ml.`id` = mld.`link_id`
WHERE mld.`lang_id` =1
AND ml.`type` = 'link'
) a
ORDER BY `order` DESC

You could possibly just do a single query, with each of the left joins in it, and sort out the resulting 'slug' column using IF statements. However this depends on exactly what you want output, and whether there are multiple matching rows on the other tables.
Something like this:-
SELECT m.identificator , ml.id AS link_id, ml.parent, ml.type,
ml.destination, ml.disabled, ml.order, mld.name AS link_name,
mld.alt , mld.title , cpd.slug
FROM wf_menu m
LEFT JOIN wf_menu_link ml ON m.id = ml.menu_id
LEFT JOIN wf_menu_link_desc mld ON ml.id = mld.link_id
LEFT JOIN wf_cms_post_desc cpd ON ml.destination = cpd.post_id AND (ml.type = 'page' OR ml.type = 'article')
LEFT JOIN wf_cms_category_desc cpd ON ml.destination = cpd.category_id AND ml.type = 'cmscat' AND mld.lang_id = cpd.lang_id
LEFT JOIN wf_shop_category_desc spd ON ml.destination = spd.category_id AND ml.type = 'shopcat' AND mld.lang_id = spd.lang_id
WHERE mld.lang_id =1
AND mld.lang_id = cpd.lang_id

I think you need to use Dynamic SQL. I mean, build your end SQL into a temporary variable and execute it:
set #query = (SELECT ...);
PREPARE st FROM #query;
EXECUTE st;
Your first case coould be something like:
SET #query= (SELECT CONCAT(GROUP_CONCAT(CONCAT('SELECT m.`identificator` , ml.id AS link_id, ml.parent, ml.type,
ml.destination, ml.disabled, ml.order, mld.`name` AS link_name,
mld.`alt` , mld.`title` , cpd.`slug` FROM `wf_menu` m LEFT JOIN `wf_menu_link` ml ON m.`id` = ml.`menu_id` ',
CASE WHEN TTYPES.type='article' THEN
CONCAT('LEFT JOIN `wf_menu_link_desc` mld ON ml.`id` = mld.`link_id` LEFT JOIN `wf_cms_post_desc` cpd ON ml.destination = cpd.post_id WHERE mld.`lang_id` =1 AND mld.`lang_id` = cpd.`lang_id` AND (ml.`type` = \'page\' OR ml.`type` = \'',TTYPES.type,'\')')
END )
SEPARATOR ' UNION '), ' SELECT NULL FROM wf_menu_link WHERE 1=2') FROM (SELECT DISTINCT wf_menu_link.`type` FROM wf_menu_link) TTYPES);
(You can complete the remainding cases)
Running that query will fill #query variable with a generated query. This generated query should be the same than you posted in your question. Then you can run it as you can see above in this answer.
This is an example/idea you have to complete it and/or check it works in your model.

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

How convert rows to columns(SQL)?

I want to do this:
Desired Output
but I actually have this:
Current Output
this is my sql code:
enter code here
SELECT `a`.`itemId` AS itemId, `a`.`donationId` AS `donationId`,
`a`.`typeId` AS `typeId`, `a`.`currencyId` AS `currencyId`,
`a`.memberId AS memberId, `a`.amount_total AS amount_total, a.ref AS
ref, a.ref_bank AS ref_bank, `a`.`hidden` AS `hidden`, a.code AS code,
concat( `b`.`first_name`, ' ', `b`.`last_name` ) AS member_name,
`c`.currencyCode AS currencyCode, `f`.`name` AS `payment_name`,
e.itemEnvelopId, e.itemId AS itemIdP, e.accountId, e.amount,
e.hidden as envelopHidden, g.NAME, g.new_number
FROM
ai_donation_items `a` LEFT JOIN ai_church_members `b` ON a.memberId = b.memberId
LEFT JOIN ai_currency `c` ON a.currencyId = c.currencyId
LEFT JOIN ai_payment_types `f` ON a.typeId = f.typeId
LEFT JOIN ai_donation_envelops_item as e on a.itemId = e.itemId
LEFT JOIN ai_accounts AS g ON e.accountId = g.accountId
WHERE `a`.`hidden` = 0 AND e.hidden = 0 and a.donationId = 1

How to do a Query on SQL Server 2008 R2 using a subquery / function on GROUP BY

When I execute this query, it works fine:
SELECT
pr.pr_nombre , cl.cl_nomcorto,
mc_cant * dbo.tipo_cambio(cr.mo_id,3,mc_fecha)/0.951 as Interes,
mc_cant * dbo.tipo_cambio(cr.mo_id,3,mc_fecha)/0.951*.049 as WH,
(select pr_id from dbo.nonplusultra(cr.pr_id) where pr_renew_ref is null) as Agrupador
FROM movcuentas mc
inner join corridas cr on mc.cr_id = cr.cr_id
inner join clientes cl on cr.cl_id = cl.cl_id
inner join prestamos pr on cr.pr_id = pr.pr_id
WHERE (mc_concepto = 'Amort Int') AND (tm_id = 3) AND MONTH(mc_fecha) = 2 AND YEAR(mc_fecha) = 2017
ORDER BY pr.pr_nombre
I get this:
Query results
Now I need to show it adding columns "Interes" and "WH" on records with same "Agrupador", something like this:
SELECT
pr.pr_nombre , cl.cl_nomcorto,
sum(mc_cant * dbo.tipo_cambio(cr.mo_id,3,mc_fecha)/0.951) as Interes,
sum(mc_cant * dbo.tipo_cambio(cr.mo_id,3,mc_fecha)/0.951*.049) as WH,
(select pr_id from dbo.nonplusultra(cr.pr_id) where pr_renew_ref is null) as Agrupador
FROM movcuentas mc
inner join corridas cr on mc.cr_id = cr.cr_id
inner join clientes cl on cr.cl_id = cl.cl_id
inner join prestamos pr on cr.pr_id = pr.pr_id
WHERE (mc_concepto = 'Amort Int') AND (tm_id = 3) AND MONTH(mc_fecha) = 2 AND YEAR(mc_fecha) = 2017
GROUP BY pr.pr_nombre , cl.cl_nomcorto, (select pr_id from dbo.nonplusultra(cr.pr_id) where pr_renew_ref is null)
ORDER BY pr.pr_nombre
And I get this error message:
Msg 144, Level 15, State 1, Line 12
Cannot use an aggregate or a subquery in an expression used for the group by list of a GROUP BY clause.
Any help will be welcome.
Can you make use of CTE here?
;WITH CTE as
(
SELECT
pr.pr_nombre , cl.cl_nomcorto,
mc_cant * dbo.tipo_cambio(cr.mo_id,3,mc_fecha)/0.951 as Interes,
mc_cant * dbo.tipo_cambio(cr.mo_id,3,mc_fecha)/0.951*.049 as WH,
(select pr_id from dbo.nonplusultra(cr.pr_id) where pr_renew_ref is null) as Agrupador
FROM movcuentas mc
inner join corridas cr on mc.cr_id = cr.cr_id
inner join clientes cl on cr.cl_id = cl.cl_id
inner join prestamos pr on cr.pr_id = pr.pr_id
WHERE (mc_concepto = 'Amort Int') AND (tm_id = 3) AND MONTH(mc_fecha) = 2 AND YEAR(mc_fecha) = 2017
ORDER BY pr.pr_nombre
)
select pr_nombre,cl_nomcorto,sum(Interes),sum(WH),Agrupador
from CTE
group by pr_nombre,cl_nomcorto,Agrupador
order by pr_nombre

how to GROUP_CONCAT with Concat

Product name supplier
A Su1
A Su1
A Su2
B Su1
C Su3
I want like this
A - su1, A-su2, B-su1, C-su3
Query:
SELECT
vtiger_salesorder.salesorder_no,
(Select
group_concat(DISTINCT concat(vtiger_products.productname, '-', vtiger_vendor.vendorname ) SEPARATOR ', ')
FROM
vtiger_salesorder
LEFT Join vtiger_inventoryproductrel ON vtiger_salesorder.salesorderid = vtiger_inventoryproductrel.id
inner Join vtiger_products ON vtiger_products.productid = vtiger_inventoryproductrel.productid
inner Join softMax_SalesOrderVendorInfo ON softMax_SalesOrderVendorInfo.salesorderid = vtiger_salesorder.salesorderid
LEFT JOIN vtiger_vendor ON softMax_SalesOrderVendorInfo.vendorid = vtiger_vendor.vendorid
where (vtiger_salesorder.salesorderid = vtiger_inventoryproductrel.id
AND vtiger_salesorder.salesorderid = vtiger_crmentity.crmid
and (softMax_SalesOrderVendorInfo.status = '0') )Group by vtiger_salesorder.salesorderid Limit 0,1) As SuName1
FROM
vtiger_salesorder
INNER JOIN vtiger_inventoryproductrel ON vtiger_salesorder.salesorderid = vtiger_inventoryproductrel.id
Inner Join vtiger_crmentity ON vtiger_salesorder.salesorderid = vtiger_crmentity.crmid
Order by vtiger_salesorder.salesorder_no
Given your original data, you can simply do this with something like:
select distinct group_concat(ProductName, '-', Supplier separator ', ')
from table t;
I have no idea what the query has to do with the question, because you already seem to have the data in the appropriate format.

Suggestions on complex sql statement

SELECT `v`.*
, GROUP_CONCAT(DISTINCT(`gg`.genre_id)) AS `genre_ids`
, GROUP_CONCAT(DISTINCT(`gg`.genre_ru)) AS `genres`
, GROUP_CONCAT(DISTINCT(`tg`.tag_id)) AS `tags_ids`
, GROUP_CONCAT(DISTINCT(`tg`.name)) AS `tags`
FROM `video` AS `v`
LEFT JOIN `video_categories` AS `gc` ON gc.video_id = v.video_id
LEFT JOIN `video_genres` AS `gg` ON gg.genre_id = gc.genre_id
LEFT JOIN `tags_relations` AS `tr` ON tr.department=18 AND tr.parent_id = v.video_id
LEFT JOIN `tags` AS `tg` ON tg.tag_id = tr.tag_id
WHERE (v.video_id IN (
SELECT gc2.video_id
FROM video_categories gc2
WHERE gc2.genre_id IN(44)
GROUP BY gc2.video_id
HAVING COUNT(gc2.video_id)=1))
AND (v.video_id IN (
SELECT gc2.parent_id
FROM tags_relations gc2
WHERE gc2.tag_id IN(14) AND gc2.department=18
GROUP BY gc2.parent_id
HAVING COUNT(gc2.parent_id)=1))
GROUP BY `v`.`video_id`
ORDER BY `v`.`video_id` DESC
Query takes 0.4s~ to run. It's because of subquery in WHERE statement:
v.video_id IN (
SELECT gc2.parent_id
FROM tags_relations gc2
WHERE gc2.tag_id IN(14) AND gc2.department=18
GROUP BY gc2.parent_id
HAVING COUNT(gc2.parent_id)=1
)
Without it, it runs 0.07s~
Maybe try something with advanced joins? shy
Thanks ;)
In MySQL, never use WHERE in (SELECT ... it is notoriously slow.
Use a join instead:
SELECT `v`.*
, GROUP_CONCAT(DISTINCT(`gg`.genre_id)) AS `genre_ids`
, GROUP_CONCAT(DISTINCT(`gg`.genre_ru)) AS `genres`
, GROUP_CONCAT(DISTINCT(`tg`.tag_id)) AS `tags_ids`
, GROUP_CONCAT(DISTINCT(`tg`.name)) AS `tags`
FROM video AS v
INNER JOIN video_categories AS gc ON gc.video_id = v.video_id
AND gc2.genre_id = '44'
LEFT JOIN video_genres AS gg ON gg.genre_id = gc.genre_id
LEFT JOIN tags_relations AS tr ON tr.department=18 AND tr.parent_id = v.video_id
LEFT JOIN tags AS tg ON tg.tag_id = tr.tag_id
INNER JOIN tags_relations tr2 ON (tr2.parent_id = v.video_id
AND tr2.tag_id = 14 AND tr2.department=18
GROUP BY `v`.`video_id`
ORDER BY `v`.`video_id` DESC
SELECT `v`.*
, GROUP_CONCAT(DISTINCT(`gg`.genre_id)) AS `genre_ids`
, GROUP_CONCAT(DISTINCT(`gg`.genre_ru)) AS `genres`
, GROUP_CONCAT(DISTINCT(`tg`.tag_id)) AS `tags_ids`
, GROUP_CONCAT(DISTINCT(`tg`.name)) AS `tags`
FROM `video` AS `v`
LEFT JOIN `video_categories` AS `gc` ON gc.video_id = v.video_id
LEFT JOIN `video_genres` AS `gg` ON gg.genre_id = gc.genre_id
LEFT JOIN `tags_relations` AS `tr` ON tr.department=18 AND tr.parent_id = v.video_id
LEFT JOIN `tags` AS `tg` ON tg.tag_id = tr.tag_id
JOIN (
SELECT gc2.video_id
FROM video_categories gc2
WHERE gc2.genre_id IN(44)
GROUP BY gc2.video_id
HAVING COUNT(gc2.video_id)=1
) vc ON v.video_id = vc.video_id
JOIN (
SELECT gc2.parent_id
FROM tags_relations gc2
WHERE gc2.tag_id IN(14) AND gc2.department=18
GROUP BY gc2.parent_id
HAVING COUNT(gc2.parent_id)=1
) tr ON v.video_id = tr.parent_id
GROUP BY `v`.`video_id`
ORDER BY `v`.`video_id` DESC
Edit:
I took a closer look at your query and think it can be reduced to the following:
SELECT `v1`.*
, GROUP_CONCAT(DISTINCT(`gg`.genre_id)) AS `genre_ids`
, GROUP_CONCAT(DISTINCT(`gg`.genre_ru)) AS `genres`
, GROUP_CONCAT(DISTINCT(`tg`.tag_id)) AS `tags_ids`
, GROUP_CONCAT(DISTINCT(`tg`.name)) AS `tags`
FROM (
SELECT v.*
FROM `video` AS `v`
LEFT JOIN `video_categories` AS `gc` ON gc.video_id = v.video_id
LEFT JOIN `tags_relations` AS `tr` ON tr.parent_id = v.video_id
WHERE gc.genre_id IN(44)
AND tr.tag_id IN(14)
AND tr.department=18
GROUP BY `v`.`video_id`
HAVING COUNT(*) = 1
) v1
LEFT JOIN `video_genres` AS `gg` ON gg.genre_id = gc.genre_id
LEFT JOIN `tags` AS `tg` ON tg.tag_id = tr.tag_id
GROUP BY v1.video_id
ORDER BY v1.video_id DESC