GROUP BY with HAVING but unrecognized table in MySQL - mysql

I have this query, and I am trying to split the answer column RES (that is divided by commas) into more rows (instead). But when I try to do that, the HAVING part is not working at all, and it's throwing: Unknow column.
This is the original query:
SELECT ad.ID_ANSWER as idRes
, IFNULL(c.NOMBRE_FACTURA,a.INTERVIEWED_NAME) AS nomPdv
, c.CODIGO
, q.`NAME` AS nombreEncuesta
, ad.ID_QUESTION AS idCue
, que.QUESTION
, GROUP_CONCAT(ad.ANSWER) AS RES
, a.LATITUDE
, a.LONGITUDE
, cm.DIRECCION
, c.NIT
, cm.NOMREPRESENTANTE
, cm.FECHA_NACIMIENTO
, a.ID_QUESTIONARY
, cm.TELEFONO, cm.FECHA_NACIMIENTO, cm.NITREPRESENTANTE,
CONCAT(cm.APELLIDO_PATERNO,' ',cm.APELLIDO_MATERNO,' ', cm.NOMBRES_CLIENTE) as RAZONSOCIAL, a.USUARIO_ID, a.FECHA_ID, R.NOMBRE AS RUTA, CASE WHEN D.NOMBRE IS NULL THEN DP.NOMBRE ELSE D.NOMBRE END AS DEPARTAMENTO, P.NOMBRE AS ENCUESTADOR
FROM VM_ANSWER AS a
JOIN VM_ANSWER_DETAIL ad
ON ad.ID_ANSWER = a.ID_ANSWER
JOIN VM_QUESTIONARY AS q
ON q.ID_QUESTIONARY = a.ID_QUESTIONARY
JOIN VM_QUESTION AS que
ON que.ID_QUESTION = ad.ID_QUESTION
JOIN VM_QUESTIONARY_RANGE AS qr
on qr.ID_QUESTIONARY = a.ID_QUESTIONARY
AND qr.OPERACION_ID = 1
JOIN AD_USUARIO U
ON U.USERNAME = a.USUARIO_ID
JOIN GL_PERSONA P
ON P.ID_PERSONA = U.ID_PERSONA
LEFT
JOIN (SELECT * FROM VP_VENDEDOR V GROUP BY V.ID_PERSONA) V ON V.ID_PERSONA = U.ID_PERSONA
LEFT JOIN VP_SUCURSAL S ON S.ID_SUCURSAL = V.ID_SUCURSAL
LEFT JOIN GL_DEPARTAMENTO D ON D.ID_DEPARTAMENTO = S.ID_DEPARTAMENTO
LEFT JOIN VP_CLIENTE AS c ON c.ID_CLIENTE = a.ID_CLIENT
LEFT JOIN VM_CLIENTE_MOVIL AS cm ON cm.ID_CLIENTE = c.ID_CLIENTE
LEFT JOIN GL_DEPARTAMENTO DP ON DP.ID_DEPARTAMENTO = cm.ID_CIUDAD
LEFT JOIN VM_RUTA_VENDEDOR RV ON RV.ID_VENDEDOR = V.ID_VENDEDOR AND RV.OPERACION_ID > 0
LEFT JOIN VM_RUTA R ON R.ID_RUTA = RV.ID_RUTA
WHERE a.OPERACION_ID = 1 AND qr.ID_BRANCH = 3 AND IF (61 = 0, TRUE, a.ID_QUESTIONARY = 61)
GROUP BY a.ID_QUESTIONARY,a.ID_ANSWER
ORDER BY a.ID_QUESTIONARY,a.ID_ANSWER
When I add the following code
LEFT JOIN GL_TIPO T ON T.ID_TIPO = que.ID_TYPE
WHERE a.OPERACION_ID = 1 AND qr.ID_BRANCH = 3 AND IF (61 = 0, TRUE, a.ID_QUESTIONARY = 61)
GROUP BY a.ID_QUESTIONARY,a.ID_ANSWER, ad.ID_ANSWER_DETAIL HAVING T.ID_TIPO=1012
ORDER BY a.ID_QUESTIONARY,a.ID_ANSWER
throws me the error of not recognized table T.ID_TIPO, but if I take off the HAVING word, the left join works normally.
this is the normal result, that as you can see in the column RES, it's divided by a comma when there is more than an answer:
I know it's complicated to understand, 1012 is a multi-select answer type from table GL_TIPO, and it's used in the table Question to define the type of it.
If you can help me to understand what I am doing wrong with the HAVING reserved word it would be awesome, but if you have any suggestion is also welcome too.

Try this:
GROUP BY a.ID_QUESTIONARY,a.ID_ANSWER, que.ID_TIPO=1012
This will put the questions with ID_TIPO=1012 into its own row, and all other ID_TIPO values will be grouped together. Both of these are nested within the ID_QUESTIONARY, ID_ANSWER groups.

Related

Mysql adding index for column type text does not improve performance while using select query

I am using InnoDB. From this question, I found out that I have to specify the length if I want to add index to columns which type is TEXT.
But after successfully adding index, the performance for the select query stay the same. Anyone know why? I did check the index with show index from tableName and the index did exist.
So it was the last two table EventResultsFinalSummary and EventResultsPrelims.
CREATE OR REPLACE VIEW ScheduleView AS
SELECT s.ScheduleID, e.EventRound, e.EventRoundsID, e.EventID, e.NumberCouplesInRound, n.NumberOnBack, eic.EventName AS 'Division',
CONCAT(a1.FirstName, ' ', a1.LastName, ' - ', a2.FirstName, ' ', a2.LastName) AS 'Couple',
s.SessionID AS 'Session', erfs.CouplePlace, c.CoupleID,
s.Timeslot, s.SubFloor ,s.itemDuration,s.HeatNumber, o.ActivityName, st.StudioName AS 'DanceStudio', a.AgeName AS 'Age', s.competition_id, erp.CoupleVotes
FROM Schedule AS s
LEFT JOIN EventRounds AS e ON s.EventRoundID = e.EventRoundsID AND s.competition_id = e.competition_id
LEFT JOIN OtherActivities AS o ON s.OtherActivitiesID = o.OtherActivitiesID AND s.competition_id = o.competition_id
LEFT JOIN EntriesEvents AS ee ON e.EventID = ee.EventID AND e.EventRound <= ee.EventRound AND e.Competition_id = ee.Competition_id
LEFT JOIN Couples AS c ON ee.EntryID = c.CoupleID AND ee.Competition_id = c.Competition_id
LEFT JOIN NumSysComps AS n ON c.CompetitorIDMan = n.CompetitorIDMan AND c.Competition_id = n.Competition_id
LEFT JOIN Attendees AS a1 ON c.CompetitorIDMan = a1.AttendeeID AND c.Competition_id = a1.Competition_id
LEFT JOIN Attendees AS a2 ON c.CompetitorIDLady = a2.AttendeeID AND c.Competition_id = a2.Competition_id
LEFT JOIN Studios AS st ON a1.StudioID = st.StudioID AND a1.Competition_id = st.Competition_id
LEFT JOIN EventsInComp AS eic ON eic.EventID = e.EventID AND eic.Competition_id = e.Competition_id
LEFT JOIN ProAmSingleDanceEvents AS psd ON eic.ProAmSingleDanceEventID = psd.ProAmSingleDanceEventID AND eic.Competition_id = psd.Competition_id
LEFT JOIN ProAmMultiDanceEvents AS pmd ON eic.ProAmMultiDanceEventID = pmd.ProAmMultiDanceEventID AND eic.Competition_id = pmd.Competition_id
LEFT JOIN Ages AS a ON (
psd.AgeID = a.AgeID AND psd.Competition_id = a.Competition_id
OR
pmd.AgeID = a.AgeID AND pmd.Competition_id = a.Competition_id
)
LEFT JOIN EventResultsFinalSummary AS erfs ON e.EventID = erfs.EventID AND c.CoupleID = erfs.CoupleID AND s.Competition_id = erfs.Competition_id
LEFT JOIN EventResultsPrelims AS erp ON e.EventID = erp.EventID AND erp.EventRound = e.EventRound AND c.CoupleID = erp.CoupleID AND s.Competition_id = erp.Competition_id
ORDER BY s.ScheduleID;
I added index to the column that I joined.
EventID, CoupleId, Competition_id for EventResultsFinalSummary and EventID, EventRound, Competition_id for EventResultsPrelims by using query like following.
My question is that when those columns have type like varchar or int, the select * query will only take 1s. But it take 26s when the type is Text.
ALTER TABLE `EventResultsPrelims` ADD INDEX(`EventID`(6));

Get data from a "log" table to a mySQL query

I need to check the data in a log table to see if the user has previously read a post. My log table is named foretag_kontaktervisadbrf2017 and it contains information about who has read a post. How can I edit my query so that i get information telling me if i have read a post or not?
This is my query so far:
SELECT
brfbolagsverket.BrfNamn
, brfextra.BrfId
, brfextra.Organisationsnr
, brfextra.Gatuadress
, brfextra.Ort
, brfextra.Lagenheter
, brfextra.ByggAr
, BrfHarFastighet.Fangdatum
FROM
(((((brfextra LEFT JOIN BrfHarFastighet ON brfextra.Organisationsnr = BrfHarFastighet.Organisationsnr)
LEFT JOIN brfkonkurs ON brfextra.Organisationsnr = brfkonkurs.Organisationsnr)
LEFT JOIN brfavford ON brfextra.Organisationsnr = brfavford.Organisationsnr)
LEFT JOIN brffusion ON brfextra.Organisationsnr = brffusion.Organisationsnr)
LEFT JOIN brflikvidation ON brfextra.Organisationsnr = brflikvidation.Organisationsnr)
LEFT JOIN brfbolagsverket ON brfextra.Organisationsnr = brfbolagsverket.Organisationsnr
WHERE
(((brfkonkurs.BolagetsStatusKod) IS NULL)
AND ((brfavford.BolagetsStatusKod) IS NULL)
AND ((brffusion.BolagetsStatusKod) IS NULL)
AND ((brflikvidation.BolagetsStatusKod) IS NULL OR (brflikvidation.BolagetsStatusKod) = 34))
In the result I need the following additional columns from the log table:
BrfId, BrfNamn, Organisationsnr, LogEntry
1, Billy, Organisationsnr, You have shown this post before
2, Carl, Organisationsnr, NULL
3, Kent, Organisationsnr, NULL
4, Sara, Organisationsnr, You have shown this post before
Please help with code I need to add to my query. I lack coding experience.
I would do this by adding a subselect like the example below. Hope it helps point you in the right direction.
SELECT
brfbolagsverket.BrfNamn
, CASE WHEN (SELECT COUNT(*) FROM foretag_kontaktervisadbrf2017 AS L WHERE L.Organisationsnr = B.Organisationsnr AND L.Foretag_kontaktID = 1247) > 0 THEN 'Lest' ELSE 'Inte lest' END AS NotificationRead
, brfextra.BrfId
, brfextra.Organisationsnr
, brfextra.Gatuadress
, brfextra.Ort
, brfextra.Lagenheter
, brfextra.ByggAr
, BrfHarFastighet.Fangdatum
FROM (((((
brfextra AS B
LEFT JOIN BrfHarFastighet ON brfextra.Organisationsnr = BrfHarFastighet.Organisationsnr)
LEFT JOIN brfkonkurs ON brfextra.Organisationsnr = brfkonkurs.Organisationsnr)
LEFT JOIN brfavford ON brfextra.Organisationsnr = brfavford.Organisationsnr)
LEFT JOIN brffusion ON brfextra.Organisationsnr = brffusion.Organisationsnr)
LEFT JOIN brflikvidation ON brfextra.Organisationsnr = brflikvidation.Organisationsnr)
LEFT JOIN brfbolagsverket ON brfextra.Organisationsnr = brfbolagsverket.Organisationsnr
WHERE (((brfkonkurs.BolagetsStatusKod) Is Null) AND ((brfavford.BolagetsStatusKod) Is Null) AND ((brffusion.BolagetsStatusKod) Is Null) AND ((brflikvidation.BolagetsStatusKod) Is Null Or (brflikvidation.BolagetsStatusKod)=34))
Im sorry if i post wrong - don't know how to reply properly to Werner Waage answer.
The query is slow when search gets more than 50-70 records - i tried to change to select like
(SELECT Foretag_kontaktervisadBrfID FROM foretag_kontaktervisadbrf2017 AS L WHERE L.Organisationsnr = B.Organisationsnr AND L.Foretag_kontaktID = '1247') AS NotificationRead
but its slow to.
My log table foretag_kontaktervisadbrf2017 have unique posts like this
Foretag_kontaktervisadBrfID, Foretag_kontaktID, Organisationsnr, Date001
1, Billy01, Acme_01, 2018-01-01
2, Carl01, Acme_02, 2018-01-02
3, Billy01, Acme_02, 2018-04-15
4, Carl01, Acme_03, 2018-14-14
Any way to get my previous speed back to the new query?
My original SQL-query worked fast even with results of 1000 records/post.
Here is another approach without using subselects, it assumes that the table foretag_kontaktervisadbrf2017 contains 0 or 1 row per user.
SELECT
brfbolagsverket.BrfNamn
, CASE WHEN L.Foretag_kontaktID IS NOT NULL THEN 'Lest' ELSE 'Inte lest' END AS NotificationRead
, brfextra.BrfId
, brfextra.Organisationsnr
, brfextra.Gatuadress
, brfextra.Ort
, brfextra.Lagenheter
, brfextra.ByggAr
, BrfHarFastighet.Fangdatum
FROM (((((
brfextra AS B
LEFT JOIN BrfHarFastighet ON brfextra.Organisationsnr = BrfHarFastighet.Organisationsnr)
LEFT JOIN brfkonkurs ON brfextra.Organisationsnr = brfkonkurs.Organisationsnr)
LEFT JOIN brfavford ON brfextra.Organisationsnr = brfavford.Organisationsnr)
LEFT JOIN brffusion ON brfextra.Organisationsnr = brffusion.Organisationsnr)
LEFT JOIN brflikvidation ON brfextra.Organisationsnr = brflikvidation.Organisationsnr)
LEFT JOIN brfbolagsverket ON brfextra.Organisationsnr = brfbolagsverket.Organisationsnr
LEFT JOIN foretag_kontaktervisadbrf2017 AS L ON L.Organisationsnr = B.Organisationsnr AND L.Foretag_kontaktID = 1247 -- This id probably needs to come from somewhere else, join in the users etc..
WHERE (((brfkonkurs.BolagetsStatusKod) Is Null) AND ((brfavford.BolagetsStatusKod) Is Null) AND ((brffusion.BolagetsStatusKod) Is Null) AND ((brflikvidation.BolagetsStatusKod) Is Null Or (brflikvidation.BolagetsStatusKod)=34))

MySQL - WHERE every value is IN

The following query selects all workunts where the inputs are "done" (subquery on line 7). This works fine... when there is only one input. How can I change this so that it requires every input to be IN that set returned by the subquery, not just one of the inputs to be present?
SELECT workunits.ID
FROM workunits
LEFT JOIN workunitInputs ON workunits.ID = workunitInputs.workunitID
WHERE workunits.ID NOT IN (SELECT workunitID FROM jobworkunitassoc)
AND (
workunitInputs.inputID IN (
SELECT workunitOutputs.outputID
FROM workunitOutputs
LEFT JOIN workunits ON workunitOutputs.workunitID = workunits.ID
LEFT JOIN jobworkunitassoc ON workunits.ID = jobworkunitassoc.workunitID
LEFT JOIN jobs ON jobworkunitassoc.jobID = jobs.ID
WHERE jobs.done = 1
)
OR workunitInputs.inputID IS NULL
)
GROUP BY workunits.ID
Thanks, Istvan.
Change that clause to:
AND (
workunitInputs.inputID NOT IN (
SELECT workunitOutputs.outputID
FROM workunitOutputs
LEFT JOIN workunits ON workunitOutputs.workunitID = workunits.ID
LEFT JOIN jobworkunitassoc ON workunits.ID = jobworkunitassoc.workunitID
LEFT JOIN jobs ON jobworkunitassoc.jobID = jobs.ID
WHERE jobs.done != 1
)
This is based on the logical tautology: All X in Y === No X in !Y
This query works for me, though it may not be the best solution:
http://pastebin.com/g9qBjQGU

MYSQL LEFT JOIN optimization with CASE

I spent some time trying to get working this SELECT with CASE but I failed... (thank to that I'm using COLASCE() now)
How could I optimize this SELECT by using CASE/IF sentences? Is this a fast way to query from different tables selected by a field?
SELECT a.folderid, a.foldername, a.contenttype, COALESCE(b.descriptor, c.descriptor, d.descriptor, e.descriptor, f.descriptor) as descriptor
FROM t_folders a
LEFT JOIN t_files b
ON a.contenttype = 'file' AND a.contentid = b.fileid
LEFT JOIN t_links c
ON a.contenttype = 'link' AND a.contentid = c.linkid
LEFT JOIN t_extfiles d
ON a.contenttype = 'extfile' AND a.contentid = d.extfileid
LEFT JOIN t_videos e
ON a.contenttype = 'video' AND a.contentid = e.videoid
LEFT JOIN t_exams f
ON a.contenttype = 'exam' AND a.contentid = f.examid
WHERE a.folderid = $folderId
ORDER BY a.folderid DESC
Using case statement will not make the query faster in your case, but since you asked for it, below is how it would look like.
SELECT a.folderid, a.foldername, a.contenttype,
(CASE a.contenttype
WHEN 'file' THEN b.descriptor
WHEN 'link' THEN c.descriptor
WHEN 'extfile' THEN d.descriptor
WHEN 'video' THEN e.descriptor
ELSE f.descriptor
END CASE) AS descriptor
FROM t_folders a
LEFT JOIN t_files b ON a.contenttype = 'file' AND a.contentid = b.fileid
LEFT JOIN t_links c ON a.contenttype = 'link' AND a.contentid = c.linkid
LEFT JOIN t_extfiles d ON a.contenttype = 'extfile' AND a.contentid = d.extfileid
LEFT JOIN t_videos e ON a.contenttype = 'video' AND a.contentid = e.videoid
LEFT JOIN t_exams f ON a.contenttype = 'exam' AND a.contentid = f.examid
WHERE a.folderid = $folderId
ORDER BY a.folderid DESC
If each of the t_files, t_links, etc tables has the folder_id field, I would also try doing a UNION on these tables and then left join the result with t_folders to get the folderid and foldername.
The joins have to be done this way because the come out of different tables. You cannot use CASE to switch which table a query is coming out of: the statement has to be parsed, including its data sources, before there are values to compare.
More to the point, CASE returns values, whereas table names are.. I don't know the technical term.. structural components of the query. It's sort of the same reason you can't select out of table "Cool_Stuff" with:
select * from "Cool_" + "Stuff"
Hope this answers your question!
You may do the following
select master.* , COALESCE(b.descriptor, c.descriptor, d.descriptor, e.descriptor, f.descriptor) as descriptor
from
( SELECT a.folderid, a.foldername, a.contenttype
FROM t_folders a
WHERE a.folderid = $folderId
ORDER BY a.folderid DESC ) master
LEFT JOIN t_files b
ON master.contenttype = 'file' AND master.contentid = b.fileid
LEFT JOIN t_links c
ON master.contenttype = 'link' AND master.contentid = c.linkid
LEFT JOIN t_extfiles d
ON master.contenttype = 'extfile' AND master.contentid = d.extfileid
LEFT JOIN t_videos e
ON master.contenttype = 'video' AND master.contentid = e.videoid
LEFT JOIN t_exams f
ON master.contenttype = 'exam' AND master.contentid = f.examid
While minimizing the result on table a, the joins operation can be optmizsed

How to write a select statement inside another select in SQL

Can anyone tell me what is wrong with this query?
it gives a syntax error near the 2nd select
SELECT b.mc_boxes_idmc_boxes,
t.idtitles,
t.title,
t.languages_idlanguages,
MAX(h.idtitle_history),
MAX(h.edition)
(SELECT h.preview, h.file WHERE h.idtitle_history = MAX(h.idtitle_history))
FROM mc_boxes_has_titles b
LEFT JOIN titles t ON b.titles_idtitles = t.idtitles
LEFT JOIN title_history h ON h.titles_idtitles = t.idtitles
WHERE b.mc_boxes_idmc_boxes = 12
AND h.edition IS NOT NULL
GROUP BY b.mc_boxes_idmc_boxes, idtitles
ORDER BY b.sortorder;
looks like you are missing a comma after MAX(h.edition)
SELECT b.mc_boxes_idmc_boxes,
t.idtitles,
t.title,
t.languages_idlanguages,
MAX(h.idtitle_history),
MAX(h.edition),
(SELECT h.preview, h.file WHERE h.idtitle_history = MAX(h.idtitle_history))
FROM mc_boxes_has_titles b
LEFT JOIN titles t ON b.titles_idtitles = t.idtitles
LEFT JOIN title_history h ON h.titles_idtitles = t.idtitles
WHERE b.mc_boxes_idmc_boxes = 12
AND h.edition IS NOT NULL
GROUP BY b.mc_boxes_idmc_boxes, idtitles
ORDER BY b.sortorder;
besides the comma, you are selecting two fields in your subquery
SELECT b.mc_boxes_idmc_boxes,
t.idtitles,
t.title,
t.languages_idlanguages,
MAX(h.idtitle_history),
MAX(h.edition),
(SELECT preview FROM title_history WHERE idtitle_history = MAX(h.idtitle_history)),
(SELECT [file] FROM title_history WHERE idtitle_history = MAX(h.idtitle_history))
FROM mc_boxes_has_titles b
LEFT JOIN titles t ON b.titles_idtitles = t.idtitles
LEFT JOIN title_history h ON h.titles_idtitles = t.idtitles
WHERE b.mc_boxes_idmc_boxes = 12
AND h.edition IS NOT NULL
GROUP BY b.mc_boxes_idmc_boxes, idtitles
ORDER BY b.sortorder;
Adding to bluefeet's answer, you may want to check for reserved words. "File" for example is a reserved word in sql server.
Alias it as a virtual table. Change something like
SELECT b.mc_boxes_idmc_boxes,
t.idtitles,
t.title,
t.languages_idlanguages,
MAX(h.idtitle_history),
MAX(h.edition)
(SELECT h.preview, h.file WHERE h.idtitle_history = MAX(h.idtitle_history))
FROM mc_boxes_has_titles b
LEFT JOIN titles t ON b.titles_idtitles = t.idtitles
LEFT JOIN title_history h ON h.titles_idtitles = t.idtitles
WHERE b.mc_boxes_idmc_boxes = 12
AND h.edition IS NOT NULL
GROUP BY b.mc_boxes_idmc_boxes, idtitles
ORDER BY b.sortorder) as virtual_column_alias;
Check this out. Hope this will work.