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
Related
I am trying to make a query for a sales report, the code I have works excellent in the aspect that it returns the correct result, however I think it can be greatly improved since I am using multiple queries to generate the columns "Total_Productos", "Total_Servicios " and "Total", I have tried some ways to adjust it but I would like to hear some advice, I attach the code and the result it shows
SELECT f.numero, f.fecha, CONCAT(c.nombre, ' ', c.apellido) AS Cliente,
(SELECT GROUP_CONCAT(' x', CONVERT(fp2.cantidad, CHAR(10)), ' ', nombre) AS Product
FROM facturas_productos fp2
INNER JOIN productos ON productos.codigo = fp2.productos_codigo
WHERE fp2.facturas_numero = fp.facturas_numero) AS Productos,
TRUNCATE((SELECT SUM(fp2.cantidad * productos.precio_venta) AS T_Producto
FROM facturas_productos fp2
INNER JOIN productos ON productos.codigo = fp2.productos_codigo
WHERE fp2.facturas_numero = fp.facturas_numero), 2) AS Total_Productos,
(SELECT GROUP_CONCAT(CONCAT(' x', CONVERT(fs2.cantidad, CHAR(10)), ' ', nombre))
FROM facturas_servicios fs2
INNER JOIN servicios ON servicios.codigo = fs2.servicios_codigo
WHERE fs2.facturas_numero = fs.facturas_numero) AS Servicios,
TRUNCATE((SELECT SUM(fs2.cantidad * servicios.precio) AS T_Servicio
FROM facturas_servicios fs2
INNER JOIN servicios ON servicios.codigo = fs2.servicios_codigo
WHERE fs2.facturas_numero = fs.facturas_numero), 2) AS Total_Servicios,
TRUNCATE((SELECT SUM(fs2.cantidad * servicios.precio) AS T_Servicio
FROM facturas_servicios fs2
INNER JOIN servicios ON servicios.codigo = fs2.servicios_codigo
WHERE fs2.facturas_numero = fs.facturas_numero) +
(SELECT SUM(fp2.cantidad * productos.precio_venta) AS T_Producto
FROM facturas_productos fp2
INNER JOIN productos ON productos.codigo = fp2.productos_codigo
WHERE fp2.facturas_numero = fp.facturas_numero), 2) AS Total
FROM facturas f
INNER JOIN clientes c ON c.ID = f.clientes_ID
INNER JOIN facturas_productos fp ON fp.facturas_numero = f.numero
INNER JOIN facturas_servicios fs ON fs.facturas_numero = f.numero
WHERE f.fecha BETWEEN "2023-01-01" AND "2023-02-04"
GROUP BY f.numero, fp.facturas_numero, fs.facturas_numero, f.fecha, c.nombre, c.apellido
ORDER BY f.numero ASC;
Result from the query above:
I tried to take from the previous queries the values to calculate the total, however it gave me another unexpected result (generated an error/wrong value), i.e:
(SELECT GROUP_CONCAT(CONCAT(' x', CONVERT(fs2.cantidad, CHAR(10)), ' ', nombre)), fs2.cantidad * servicios.precio AS Monto
FROM facturas_servicios fs2
INNER JOIN servicios ON servicios.codigo = fs2.servicios_codigo
WHERE fs2.facturas_numero = fs.facturas_numero) AS Servicios
generates: Error Code: 1241. Operand should contain 1 column(s)
More info: I created the database from a diagram using forward engineer and not from scripts (still learning at university)
Database EER Diagram
If you are running MySQL >= 8.0.14, you can move your correlated sub-queries to lateral derived tables -
SELECT f.numero, f.fecha, CONCAT(c.nombre, ' ', c.apellido) AS Cliente,
fp.Productos, fp.Total_Productos,
fs.Servicios, fs.Total_Servicios,
IFNULL(fs.Total_Servicios, 0) + IFNULL(fp.Total_Productos, 0) AS Total
FROM facturas f
INNER JOIN clientes c ON c.ID = f.clientes_ID
LEFT JOIN LATERAL (
SELECT
GROUP_CONCAT('x', fp2.cantidad, ' ', nombre SEPARATOR ', ') AS Productos,
SUM(fp2.cantidad * productos.precio_venta) AS Total_Productos
FROM facturas_productos fp2
INNER JOIN productos ON productos.codigo = fp2.productos_codigo
WHERE fp2.facturas_numero = f.numero
) fp ON 1 = 1
LEFT JOIN LATERAL (
SELECT
GROUP_CONCAT('x', fs2.cantidad, ' ', nombre SEPARATOR ', ') AS Servicios,
SUM(fs2.cantidad * servicios.precio) AS Total_Servicios
FROM facturas_servicios fs2
INNER JOIN servicios ON servicios.codigo = fs2.servicios_codigo
WHERE fs2.facturas_numero = f.numero
) fs ON 1 = 1
WHERE f.fecha BETWEEN '2023-01-01' AND '2023-02-04'
ORDER BY f.numero ASC;
I have changed the joins to LEFT JOIN LATERAL as I assume it is possible for an invoice to contain products but not services, and vice versa.
An alternative approach, which does not require MySQL >= 8.0.14, is to aggregate all the products and services in their derived tables, instead of doing the lateral join -
SELECT f.numero, f.fecha, CONCAT(c.nombre, ' ', c.apellido) AS Cliente,
fp.Productos, fp.Total_Productos,
fs.Servicios, fs.Total_Servicios,
IFNULL(fs.Total_Servicios, 0) + IFNULL(fp.Total_Productos, 0) AS Total
FROM facturas f
INNER JOIN clientes c ON c.ID = f.clientes_ID
LEFT JOIN (
SELECT
fp.facturas_numero,
GROUP_CONCAT('x', fp.cantidad, ' ', nombre SEPARATOR ', ') AS Productos,
SUM(fp.cantidad * productos.precio_venta) AS Total_Productos
FROM facturas_productos fp
INNER JOIN productos ON productos.codigo = fp.productos_codigo
GROUP BY fp.facturas_numero
) fp ON f.numero = fp.facturas_numero
LEFT JOIN (
SELECT
fs.facturas_numero,
GROUP_CONCAT('x', fs.cantidad, ' ', nombre SEPARATOR ', ') AS Servicios,
SUM(fs.cantidad * servicios.precio) AS Total_Servicios
FROM facturas_servicios fs
INNER JOIN servicios ON servicios.codigo = fs.servicios_codigo
GROUP BY fs.facturas_numero
) fs ON f.numero = fs.facturas_numero
WHERE f.fecha BETWEEN '2023-01-01' AND '2023-02-04'
ORDER BY f.numero ASC;
This may be a little bit faster when retrieving all invoices but will probably be slower when retrieving a small subset of a large number of invoices.
And here's a db<>fiddle
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
I have 3 tables in my db
1)cushbu_users (id,first_name,last_name)
2)cushbu_art (id,user_id(FK cushbu_user),title,base_price etc...) -for store user arts
3)cushbu_mark_user_favorites (id,user_id(FK cushbu_user),art_id(FK cushbu_art)) -for marking favourite items
I want to fetch the all art items of a particular user favourited
with count of favourites each art (stored in cushbu_mark_usier_favorites table )
Here is my query
SELECT
cushbu_art.id AS art_id,
cushbu_art.title,
cushbu_art.base_price,
cushbu_art.image_name,
CONCAT(
cushbu_users.first_name,
' ',
cushbu_users.last_name
) AS artist_name,COUNT(cushbu_mark_user_favorites.art_id)
FROM
cushbu_art
JOIN cushbu_mark_user_favorites ON cushbu_mark_user_favorites.art_id = cushbu_art.id
JOIN cushbu_users ON cushbu_users.id = cushbu_art.artist_id
LEFT JOIN cushbu_mark_user_favorites ON cushbu_art.id=cushbu_mark_user_favorites.art_id
WHERE
cushbu_mark_user_favorites.user_id = 68
But i got Not unique table/alias: 'cushbu_mark_user_favorites' this join statement
LEFT JOIN cushbu_mark_user_favorites ON cushbu_art.id=cushbu_mark_user_favorites.art_id
UPDATE
SELECT
a.id AS art_id,
a.title,
a.base_price,
a.image_name,
CONCAT(
c.first_name,
' ',
c.last_name
) AS artist_name,COUNT(b.art_id)
FROM
cushbu_art a
JOIN cushbu_mark_user_favorites b ON b.art_id = a.id
JOIN cushbu_users c ON c.id = a.artist_id
LEFT JOIN b ON a.id=b.art_id
WHERE
b.user_id = 68
Try below query.
SELECT
cushbu_art.id AS art_id,
cushbu_art.title,
cushbu_art.image_name,
CONCAT(
cushbu_users.first_name,
' ',
cushbu_users.last_name
) AS artist_name , b.favorites_count as total_fav
FROM
cushbu_mark_user_favorites
LEFT JOIN cushbu_art ON cushbu_art.id=cushbu_mark_user_favorites.art_id
LEFT JOIN cushbu_users ON cushbu_users.id = cushbu_art.artist_id
LEFT JOIN (SELECT art_id,count(*) as favorites_count FROM cushbu_mark_user_favorites GROUP BY art_id) as b ON b.art_id=cushbu_art.id
WHERE cushbu_mark_user_favorites.user_id=1
GROUP BY cushbu_art.id
Hope this will helpful to you.
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.
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.