Select in SQL Server don't work in MySQL, Stuff Function - mysql

Currently I have a select done in SQL Server and must have the same result for MySQL, achieving a scrip that works in the two would be even better . Below the script:
select STUFF( (SELECT ', ' + m_e.NAME + '=' + CAST(v.VALUE AS VARCHAR(MAX)) FROM MMP_USER_METADATA_INSTANCE i
left outer join MMP_USER_METADATA_INST_VALUE v on (i.id=v.USER_METADATA_INSTANCE_ID)
left outer join MMP_METADATA_ENTRY m_e on (v.METADATAENTRY_ID=m_e.id)
WHERE (u.id = i.USER_ID)
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)') ,1,2,'') AS 'Campos Adicionais' from mmp_user u
Tables:
MMP_USER_METADATA_INSTANCE,
MMP_USER_METADATA_INST_VALUE,
MMP_METADATA_ENTRY,
MMP_USER.
Result:
<table border="1"><tr BGCOLOR="#CCCCFF"><th>Campos Adicionais</th></tr>
<tr><td>Skype=Testes, Centro de Custo=16, Endereço Bairro=Teste, Endereço Cidade=, Estado Civil=44, Filhos=38, Graduação Curso=, Graduação Faculdade=Teste, Nivel de Idioma Inglês=46, Nivel de Idioma Espanhol=46, Outro Idioma=Teste, Link Linkedin=, Link Facebook=Teste, Esporte=teste, Time de Futebol=teste</td></tr>
</table>

In MySQL, you want something like this:
select (SELECT group_concat(m_e.NAME, '=', value separator ',')
FROM MMP_USER_METADATA_INSTANCE i left outer join
MMP_USER_METADATA_INST_VALUE v
on i.id = v.USER_METADATA_INSTANCE_ID left outer join
MMP_METADATA_ENTRY m_e
on v.METADATAENTRY_ID = m_e.id
WHERE u.id = i.USER_ID
) `Campos Adicionais`
from mmp_user u;

Related

Reduce multiple queries for reporting

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

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

Get column where relation is not NULL

I have a database which was migrated from SQL Server to MySQL. I had an existing query in SQL Server to get the value of a column where the relation is not null, I mean, if the relation between two tables is null then it means that there should be a relation with another table.
This is the query I was using:
SELECT C.expediente,
C.status,
Sum(M.monto) AS monto,
Sum(M.interes) AS interes,
Sum(M.iva) AS iva,
Sum(M.capital) AS capital,
M.fecha_mov,
AB.tipo_abono,
AB.id_deposito,
Isnull(Min(tg.nombre), Min(tp.nombcomp)) AS nombreGrupo
FROM movimientos AS M
JOIN acreditados AS A
ON A.id_acreditado = M.id_acreditado
JOIN creditos AS C
ON C.id_credito = A.id_credito
JOIN abonos AS AB
ON AB.id_movimiento = M.id_movimiento
OUTER apply (SELECT TOP 1 G.nombre
FROM grupos G
WHERE G.id_credito = C.id_credito) tg
OUTER apply (SELECT TOP 1 P.nombres + ' ' + P.apellido_paterno + ' '
+ P.apellido_materno AS NombComp
FROM personas P
WHERE A.id_persona = P.id_persona) tp
GROUP BY M.fecha_mov,
AB.tipo_abono,
AB.id_deposito,
C.expediente,
C.status
ORDER BY M.fecha_mov
But it seems that MySQL has no OUTER APPLY or ISNULL. How can I translate this query to MySQL?
You have a couple of issues to review:
1 - The APPLY operator is not supported in MySQL. However, for your given usage, it looks like you can probably just use a LEFT OUTER JOIN.
2 - MySQL does not support TOP. Instead, use LIMIT. However, I don't think you need it in this case since you are using MIN of each of those fields.
3 - To concatenate strings in MySQL, use CONCAT vs "+".
4 - Finally, I prefer using COALESCE in MySQL to check for NULLs. There are other options though.
So putting it all together, this should be close (untested):
SELECT C.expediente,
C.status,
Sum(M.monto) AS monto,
Sum(M.interes) AS interes,
Sum(M.iva) AS iva,
Sum(M.capital) AS capital,
M.fecha_mov,
AB.tipo_abono,
AB.id_deposito,
COALESCE(MIN(tg.nombre), MIN(tp.nombcomp)) AS nombreGrupo
FROM movimientos AS M
JOIN acreditados AS A
ON A.id_acreditado = M.id_acreditado
JOIN creditos AS C
ON C.id_credito = A.id_credito
JOIN abonos AS AB
ON AB.id_movimiento = M.id_movimiento
LEFT OUTER JOIN (
SELECT id_credito, nombre
FROM grupos
) tg ON tg.id_credito = C.id_credito
LEFT OUTER JOIN (
SELECT id_persona, CONCAT(nombres,' ',apellido_paterno,' ',apellido_materno) AS NombComp
FROM personas
) tp ON A.id_persona = tp.id_persona
GROUP BY M.fecha_mov,
AB.tipo_abono,
AB.id_deposito,
C.expediente,
C.status
ORDER BY M.fecha_mov
You may not need some of those fields in your GROUP BY -- just your DISTINCT fields needed.
I think this turns it into a valid MySQL query:
SELECT C.expediente, C.status, Sum(M.monto) AS monto, Sum(M.interes) as interes,
Sum(M.iva) as iva, Sum(M.capital) as capital,
M.fecha_mov, AB.tipo_abono, AB.id_deposito,
coalesce(Min(tg.nombre), Min(tp.nombcomp)) AS nombreGrupo
FROM movimientos M join
acreditados A
ON A.id_acreditado = M.id_acreditado join
creditos C
ON C.id_credito = A.id_credito join
abonos AB
ON AB.id_movimiento = M.id_movimiento join
(select g.id_credito, max(g.nombre) -- arbitrary nombre
from grupos g
group by g.id_credito
) tg
on tG.id_credito = C.id_credito join
(SELECT P.id_persona, concat_ws(' ', P.nombres, P.apellido_paterno, P.apellido_materno) AS NombComp
FROM personas P
group by p.id_persona
) tp
on A.id_persona = tP.id_persona
GROUP BY M.fecha_mov, AB.tipo_abono, AB.id_deposito, C.expediente, C.status
ORDER BY M.fecha_mov
I replaced the isnull() with coalesce() -- if you are going between databases, use standard SQL where possible. I replaced the + for concatenation with concat_ws(). Note there is a small difference . . . if one of the fields is NULL, then the MySQL value will treat it as ''.
I replaced the cross apply with an aggregate. You use top 1 without an order by, so this fetches an arbitrary row. So, this version arbitrarily chooses the maximum value.

How can I merge these SQL queries

I need to merge this query
SELECT
*,
(SELECT
CONCAT(c.firstname, ' ', c.lastname)
FROM
wwwpser_customer c
WHERE
c.customer_id = o.customer_id) AS customer
FROM
wwwpser_order o
WHERE
o.order_id = '20'
with
SELECT
orders . *, wwwpser_comuna.provincia_id AS payment_provincia_id
FROM
wwwpser_order orders
LEFT JOIN
wwwpser_comuna ON (orders.payment_city = wwwpser_comuna.comuna_id)
SQL syntax is new for me so I need a little help with this, thx
SELECT CONCAT(c.firstname, ' ', c.lastname)
, wc.provincia_id
, o.*
FROM wwwpser_order o
LEFT JOIN
wwwpser_customer c
ON c.customer_id = o.customer_id
LEFT JOIN
wwwpser_comuna wc
ON wc.comuna_id = o.payment_city
WHERE o.order_id = 20
It looks like this should be your solution.
SELECT
o.*, -- modified (qualified the
(SELECT -- asterisk)
CONCAT(c.firstname, ' ', c.lastname)
FROM
wwwpser_customer c
WHERE
c.customer_id = o.customer_id) AS customer,
c.provincia_id AS payment_provincia_id -- added from second query
FROM
wwwpser_order o
LEFT JOIN -- added from second query
wwwpser_comuna c ON (o.payment_city = c.comuna_id) -- added from second query
WHERE
o.order_id = '20'
I strongly recommend learning about the general SQL syntax, though. There are some useful examples in the MySQL tutorials

Multiple many-to-many JOINs in a single mysql query without Cartesian Product

At the moment I can get the results I need with two seperate SELECT statements
SELECT
COUNT(rl.refBiblioID)
FROM biblioList bl
LEFT JOIN refList rl ON bl.biblioID = rl.biblioID
GROUP BY bl.biblioID
SELECT
GROUP_CONCAT(
CONCAT_WS( ':', al.lastName, al.firstName )
ORDER BY al.authorID )
FROM biblioList bl
LEFT JOIN biblio_author ba ON ba.biblioID = bl.biblioID
JOIN authorList al ON al.authorID = ba.authorID
GROUP BY bl.biblioID
Combining them like this however
SELECT
GROUP_CONCAT(
CONCAT_WS( ':', al.lastName, al.firstName )
ORDER BY al.authorID ),
COUNT(rl.refBiblioID)
FROM biblioList bl
LEFT JOIN biblio_author ba ON ba.biblioID = bl.biblioID
JOIN authorList al ON al.authorID = ba.authorID
LEFT JOIN refList rl ON bl.biblioID = rl.biblioID
GROUP BY bl.biblioID
causes the author result column to have duplicate names. How can I get the desired results from one SELECT statement without using DISTINCT? With subqueries?
If subselects are acceptable, I believe you could make this happen by doing something like this:
SELECT
y.authors,
COUNT(rl.refBiblioID)
FROM
(SELECT
bl.biblioId,
GROUP_CONCAT(
CONCAT_WS(':', al.lastName, al.firstName)
ORDER BY al.authorID) AS authors
FROM biblioList bl
LEFT JOIN biblio_author ba ON ba.biblioID = bl.biblioID
JOIN authorList al ON al.authorID = ba.authorID
GROUP BY bl.biblioID) y
LEFT JOIN refList rl ON (y.biblioID = rl.biblioID)
GROUP BY y.biblioID
Another solution would be to add DISTINCT to your GROUP_CONCAT, but that was not what you wanted?
GROUP_CONCAT(
DISTINCT(CONCAT_WS(':', al.lastName, al.firstName) ORDER BY al.authorID)),