sql request too long ... How to simplify? - mysql

i would like to reduce the process time of my SQL request (actually it runs 10 minutes ...)
I think the problem come from the nested SQL queries.
(sorry for my english, i'm french student)
SELECT DISTINCT `gst.codeAP21`, `gst.email`, `gst.date`, `go.amount`
FROM globe_statistique
JOIN globe_customers ON `gst.codeAP21`=`gc.codeAP21`
JOIN globe_orders ON `gc.ID`=`go.FK_ID_customers`
WHERE `gst.page` = 'send_order'
AND `gst.date` = FROM_UNIXTIME(`go.date`,'%%Y-%%m-%%d')
UNION
SELECT DISTINCT `gst.codeAP21`, `gst.email`, `gst.date`, '-'
FROM globe_statistique
WHERE `gst.page` NOT LIKE 'send_order' "
AND (`gst.codeAP21`,`gst.date`) NOT IN
( SELECT `gst.codeAP21`,`gst.date` FROM globe_statistique
WHERE `gst.page`='send_order');
Thanks

try this:
SELECT DISTINCT `gst.codeAP21`, `gst.email`, `gst.date`, `go.amount`
FROM globe_statistique
JOIN globe_customers ON `gst.codeAP21`=`gc.codeAP21`
JOIN globe_orders ON `gc.ID`=`go.FK_ID_customers`
WHERE `gst.page` = 'send_order'
AND `gst.date` = FROM_UNIXTIME(`go.date`,'%%Y-%%m-%%d')
UNION
SELECT DISTINCT t1.`gst.codeAP21`, t1.`gst.email`, t1.`gst.date`, '-'
FROM globe_statistique t1
left join globe_statistique t2 on t1.gst.page =t2.gst.page and t1.gst.date =t2.gst.date and t2.gst.page =send_order
WHERE `gst.page` <> 'send_order' AND t2.gst.date is null
But i recomment to rename your column names and remove the dots.
Also use EXPLAIN to find out why the query is slow and add the correct index

try to avoid the use of distinct. To this end, UNION ALL should be used. Group by at the end gives the same result:
select codeAP21, email, date, amount
from ( --> your query without distinct but with UNION ALL <-- )
group by codeAP21, email, date, amount
see: Huge performance difference when using group by vs distinct

Related

Using the results of a function multiple times for duplicates - SQL

I am trying to produce a result that shows duplicates in a table. One method I found for getting duplicates and showing them is to run the select statement again through an inner join. However, one of my columns needs to be the result of a function, and the only thing I can think to do is use an alias, however I can't use the alias twice in a SELECT statement.
I am not sure what the best way to run this code for getting the duplicates I need.
My code below
SELECT EXTRACT(YEAR_MONTH FROM date) as 'ndate', a.transponderID
FROM dispondo_prod_disposition.event a
inner JOIN (SELECT EXTRACT(YEAR_MONTH FROM date) as ???,
transponderID, COUNT(*)
FROM dispondo_prod_disposition.event
GROUP BY mdate, transponderID
HAVING count(*) > 1 ) b
ON ndate = ???
AND a.transponderID = b.transponderID
ORDER BY b.transponderID
SELECT b.ndate, transponderID
FROM dispondo_prod_disposition.event a
INNER JOIN ( SELECT EXTRACT(YEAR_MONTH FROM date) as ndate,
transponderID
FROM dispondo_prod_disposition.event
GROUP BY 1, 2
HAVING COUNT(*) > 1 ) b USING (transponderID)
WHERE b.ndate = ??? -- for example, WHERE b.ndate = 202201
ORDER BY transponderID

SUM of COUNT on distinct columns in SQL Table / MySQL

I am trying to perform a SUM based on multiple distinct counts for specific columns on a SQL table. The issue so far is I can am unable to perform this sum while I thought the synthax would be okay. But it seems not since I constantly get an issue from this query.
select SUM(`s1`.`t1`) from (
select
COUNT(DISTINCT s1_global) from NPS_deploiement_synthese as s1 where hubspot_company_id = 2436352252
union
select
COUNT(DISTINCT s2_global) from NPS_deploiement_synthese as s1 where hubspot_company_id = 2436352252
) as t1;
You don't need a subquery at all:
select COUNT(DISTINCT s1_global) + COUNT(DISTINCT s2_global)
from NPS_deploiement_synthese s
where hubspot_company_id = 2436352252;
Your version could conceivably work, but the subquery needs column aliases.
You can add the 2 count():
select
COUNT(DISTINCT s1_global) + COUNT(DISTINCT s2_global)
from NPS_deploiement_synthese as s1
where hubspot_company_id = 2436352252

Is there a better way to do this query?

I'm kind of new to MYSQL, this query works but wonder if there's a more efficient way.
I have 2 tables...client_table and client_skills. Both tables have a 'client_id' column. I'm trying to select only the clients that match all of the requested skill code and types
This is what I first tried... (doesn't work unless you change AND to OR)
SELECT * FROM client_table
LEFT JOIN client_skills ON client_table.client_id = client_skills.client_id
WHERE (skill_code='97' AND skill_type='0')
AND (skill_code='65' AND skill_type='0')
AND (skill_code='23' AND skill_type='5')
Then I tried this... (which works and returns the results I want it to)
SELECT * FROM client_table
WHERE client_id IN
(SELECT client_id FROM client_skills WHERE (skill_code='97' AND skill_type='0'))
AND client_id IN
(SELECT client_id FROM client_skills WHERE (skill_code='65' AND skill_type='0'))
AND client_id IN
(SELECT client_id FROM client_skills WHERE (skill_code='23' AND skill_type='5'))
But if there is a shorter or more efficient way to do that I'd love to learn it.
Thanks for your help
your 1st query modified using OR is not bad. and you can do with UNION:
SELECT client_id FROM client_skills WHERE (skill_code='97' AND skill_type='0')
UNION
SELECT client_id FROM client_skills WHERE (skill_code='65' AND skill_type='0')
UNION
SELECT client_id FROM client_skills WHERE (skill_code='23' AND skill_type='5')
EDITED
you can accomplish something like this. SELF JOIN is required. (not tested on you data):
SELECT t1.client_id
FROM client_skills t1 JOIN client_skills t2 ON t1.client_id = t2.client_id
AND t1.skill_code='97' AND t1.skill_type='0'
AND t2.skil_code='65' AND t2.skill_type='0'
JOIN client_skills t3 ON t3.client_id = t1.client_id
AND t3.skil_code='23' AND t3.skill_type='5'
is this what you're asking for since you wanted to use AND instead of OR
sqlFiddle example in my example only Jeff has all 3 skills (of that skill_code and skill_type)
SELECT c.*
FROM client_table c,
client_skills s1,
client_skills s2,
client_skills s3
WHERE
c.client_id = s1.client_id AND s1.skill_code=97 AND s1.skill_type=0
AND c.client_id = s2.client_id AND s2.skill_code=65 AND s2.skill_type=0
AND c.client_id = s3.client_id AND s3.skill_code=23 AND s3.skill_type=5
It's the same logic as your second query.
the second one is slower than the first one since you are doing 4 queries, so between those two example just go with the first one with OR instead of AND.
There may be better/faster queries, but that depends on the requirements and your table's indexes
For example, do you really need skill_type? can you have two skills with the same code and different type? if all skill codes are different, just do:
SELECT * FROM client_table
LEFT JOIN client_skills ON client_table.client_id = client_skills.client_id
WHERE skill_code IN ('97','65','23')
if you have an index on skill_code then the query would be faster too
EDIT: ok, now I understand your question, you need at least 2 queries, one to get all client ids that matches the tree skills and one to get clients with those ids, try this:
SELECT * from client_table WHERE client_id IN (
SELECT client_id FROM client_skills WHERE (skill_code='97' AND skill_type='0') OR
(skill_code='65' AND skill_type='0') OR (skill_code='23' AND skill_type='5')
GROUP BY client_id HAVING count(*) = 3)
what you are doing there is:
get all client_skills records the matches any of your three desired skills
group them by client_id
select only the client_id for groups that has exactly 3 records (it means those groups have all three skills)
select all clients who's ids are in the ids returned by the subquery
I think that's be fastest approach, only 2 queries, I don't think it can be done with just one query
NOTE: that query is not tested, it's the idea, you may need to play a little with HAVING and GROUP_BY
SELECT
client_table.*
,SUM(
IF( skill_code='97' AND skill_type='0' ,1 ,0 )
+
IF( skill_code='65' AND skill_type='0' ,1 ,0 )
+
IF( skill_code='23' AND skill_type='5' ,1 ,0 )
) AS skill_code_type_count
FROM
client_table
LEFT JOIN client_skills ON client_table.client_id = client_skills.client_id
GROUP BY
client_table.client_id
HAVING
skill_code_type_count >= 3

Mysql: same query, different results

EDIT:
Sorry about unreadable query, I was under deadline. I managed to solve problem by breaking this query into two smaller ones, and doing some business logic in Java. Still want to know why this query can random times return two different results.
So, it randomly returns once all expected results, other time just half. I noticed that when I write it join per join, and execute after each join, in the end it returns all expected results. So am wandering if there's some kind of MySql memory or other limitation that it doesn't take whole tables in joins. Also read on undeterministic queries but not sure what to tell.
Please help, ask if needs clarification, and thank you in advance.
RESET QUERY CACHE;
SET SQL_BIG_SELECTS=1;
set #displayvideoaction_id = 2302;
set #ticSessionId = 3851;
select richtext.id,richtextcross.name,richtextcross.updates_demo_field,richtext.content from
(
select listitemcross.id,name,updates_demo_field,listitem.text_id from
(
select id,name, updates_demo_field, items_id from
(
SELECT id, name, answertype_id, updates_demo_field,
#student:=CASE WHEN #class <> updates_demo_field THEN 0 ELSE #student+1 END AS rn,
#class:=updates_demo_field AS clset FROM
(SELECT #student:= -1) s,
(SELECT #class:= '-1') c,
(
select id, name, answertype_id, updates_demo_field from
(
select manytomany.questions_id from
(
select questiongroup_id from
(
select questiongroup_id from `ticnotes`.`scriptaction` where ticsession_id=#ticSessionId and questiongroup_id is not null
) scriptaction
inner join
(
select * from `ticnotes`.`questiongroup`
) questiongroup on scriptaction.questiongroup_id=questiongroup.id
) scriptgroup
inner join
(
select * from `ticnotes`.`questiongroup_question`
) manytomany on scriptgroup.questiongroup_id=manytomany.questiongroup_id
) questionrelation
inner join
(
select * from `ticnotes`.`question`
) questiontable on questionrelation.questions_id=questiontable.id
where updates_demo_field = 'DEMO1' or updates_demo_field = 'DEMO2'
order by updates_demo_field, id desc
) t
having rn=0
) firstrowofgroup
inner join
(
select * from `ticnotes`.`multipleoptionstype_listitem`
) selectlistanswers on firstrowofgroup.answertype_id=selectlistanswers.multipleoptionstype_id
) listitemcross
inner join
(
select * from `ticnotes`.`listitem`
) listitem on listitemcross.items_id=listitem.id
) richtextcross
inner join
(
select * from `ticnotes`.`richtext`
) richtext on richtextcross.text_id=richtext.id;
My first impression is - don't use short cuts to describe your tables. I am lost at which td3 is where ,then td6, tdx3... I guess you might be lost as well.
If you name your aliases more sensibly there will be less chance to get something wrong and mix 6 with 8 or whatever.
Just a sugestion :)
There is no limitation on mySQL so my bet would be on human error - somewhere there join logic fails.

SQL: Display multiple record values in one field from a subquery

I have an SQL LIKE:
SELECT S.*,
(SELECT I.NAME FROM institution I, inst_map IM
WHERE IM.STUDENT = S.ID AND IM.INSTITUTION = I.ID) as INSTITUTIONS
FROM student S
In this case it is possible for my subquery to return multiple records (I will get an error: Subquery returns more than 1 row).
How to show those multiple values from my subquery in one field (in my case INSTITUTIONS ) separated by commas?
All ideas are welcome.
Try this query -
SELECT s.*, GROUP_CONCAT(t.NAME) INSTITUTIONS FROM student s
LEFT JOIN (SELECT * FROM institution i
JOIN inst_map im
ON im.INSTITUTION = i.ID
) t
ON s.ID = t.STUDENT
GROUP BY s.ID
The GROUP_CONCAT function will help you to get values separated by commas.
DECLARE #List VARCHAR(5000)
SELECT #List = COALESCE(#List + ', ' + Display, Display)
FROM TestTable
Order By Display
query is taken from following link, and the article explain the query perfectly, I hope it works
http://www.mitchelsellers.com/blogs/articletype/articleview/articleid/289/creating-comma-separated-list-in-sql.aspx
P.S Its for SQL Server, i guess