MYSQL group_concat with and IF - mysql

Have a date field that I am getting out of my DB with the following;
PS Here is more of the query using a join to get the dates from the date table.
SELECT event,event_name,
GROUP_CONCAT(DATE_FORMAT(ed.date,'%b %e') ORDER BY ed.date SEPARATOR ',') as date2
FROM events ev
LEFT JOIN event_dates ed ON ev.eid=ed.eid
WHERE ev.yr='2013'
GROUP BY ev.eid
This produces this list of dates that takes up way to much space.
May 16,May 23,May 30,Jun 6,Jun 20
I want it to look like
May 16,23,30,Jun 6,20
Here is the query I tried. but it doesn't work because the sub-query doesn't seem to know the event id. guessing i might need to convert it to a join??
SELECT DISTINCT ev.event_id,
GROUP_CONCAT(DISTINCT DATE_FORMAT(race_date,'%a') ORDER BY race_date
SEPARATOR ', ') as date1,
(SELECT GROUP_CONCAT(dm) FROM
(SELECT CONCAT(
MONTHNAME(race_date),
' ',
GROUP_CONCAT(DAY(race_date) ORDER BY race_date)
) as dm
FROM event_dates ed1 WHERE ed1.event_id=ev.event_id
GROUP BY MONTH(race_date))as t) as date2
FROM events ev
JOIN event_dates ed ON ev.event_id = ed.event_id AND ev.race_year = ed.race_year
GROUP BY event_id

SELECT GROUP_CONCAT(d) FROM (
SELECT CONCAT(
MONTHNAME(date),
' ',
GROUP_CONCAT(DAY(date) ORDER BY date)
) AS d
FROM my_table
GROUP BY MONTH(date)
) t

Related

MySql Inner join and exclude

I have the following query. I need it to include all records from the 'yahrzeit' and tbldecedent table and the ones that are a match (dupes) should only be listed once.
SELECT *, Count(*)
FROM yahrzeit
WHERE confirmed = 1
INNER JOIN tbldecedent ON CONCAT( yahrzeit.firstName, ' ', yahrzeit.middleName, ' ', yahrzeit.lastName ) = tbldecedent.Name
AND DATE_FORMAT( CONCAT( yahrzeit.gregorianYear, '-', yahrzeit.gregorianMonthNum, '-', yahrzeit.gregorianDay ) , '%Y-%m-%d' ) = tbldecedent.EngDate
GROUP BY tbldecedent.Name, tbldecedent.EngDate
Where clauses belong after the joins.
Since we're using outer joins we have to make sure the where clause criteria for the matching records is moved to the join or the outer join is negated.
in mySQL to simulate a full outer join we simple do a left and right join with a union ALL (union does a distinct which removes the duplicates)
SELECT tbldecedent.Name, tbldecedent.EngDate, Count(*) as Cnt
FROM yahrzeit
LEFT JOIN tbldecedent
ON CONCAT( yahrzeit.firstName, ' ', yahrzeit.middleName, ' ', yahrzeit.lastName ) = tbldecedent.Name
AND DATE_FORMAT( CONCAT( yahrzeit.gregorianYear, '-', yahrzeit.gregorianMonthNum, '-', yahrzeit.gregorianDay ) , '%Y-%m-%d' ) = tbldecedent.EngDate
WHERE yahrzeit.confirmed = 1
AND tblDecedent.name is null -- add this to only show no matches.
GROUP BY tbldecedent.Name, tbldecedent.EngDate
UNION ALL
SELECT tbldecedent.Name, tbldecedent.EngDate, Count(*) as cnt
FROM yahrzeit
RIGHT JOIN tbldecedent
ON CONCAT( yahrzeit.firstName, ' ', yahrzeit.middleName, ' ', yahrzeit.lastName ) = tbldecedent.Name
AND DATE_FORMAT( CONCAT( yahrzeit.gregorianYear, '-', yahrzeit.gregorianMonthNum, '-', yahrzeit.gregorianDay ) , '%Y-%m-%d' ) = tbldecedent.EngDate
AND yhrzeit.confirmed = 1
WHERE CONCAT( yahrzeit.firstName, ' ', yahrzeit.middleName, ' ', yahrzeit.lastName ) is null -- add this to only show no matches.
GROUP BY tbldecedent.Name, tbldecedent.EngDate
To better understand joins I recommend: https://blog.codinghorror.com/a-visual-explanation-of-sql-joins/ the venn diagram approach is a good one.
Lastly, I don't recommend a select *, count() with a group by containing only two fields. Select should only include the values in the group by plus
aggregates or constants. Current version of MySQL wouldn't let you get away with this without changing a global setting, and other engines simply don't support this method. MySQL extends the group by to allow it; but the results can be unexpected for the columns not listed in the group by . More on that in the docs: https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html

SQL query to combine total of two fields

I ought to combine two result fields based on my requirement. For example, below query provides the result as shown. But I need a case statement that states that both 'wind' and 'wind c' are the same, hence combine its total.
SELECT result, COUNT(*) AS total from(
SELECT t.Id AS Id,
CASE
WHEN LTRIM(RTRIM(AC)) = ' ' THEN AG
WHEN LOWER(AC) IS NOT NULL THEN LOWER(AC)
ELSE LOWER(AG)
END AS result,MaxDate,
FROM [DC_20160601] t
INNER JOIN ( SELECT Id, MAX(DateTime) AS MaxDate
FROM [DC_20160601]
GROUP BY Id) tm
ON t.Id = tm.Id AND t.DateTime = tm.MaxDate)
GROUP BY result
Current Result:
Result Total
Wind 1212
Wind c 345
sqrim 321
sqrim mob 123
Expected Result:
Result Total
Wind mobile 1557
Sqrim mobile 444
You can select the first word in a string via substring_index
SELECT SUBSTRING_INDEX(`result`, ' ', 1);
Now group by the first word of result
SELECT SUBSTRING_INDEX(`result`, ' ', 1), COUNT(*) AS total from(
SELECT t.Id AS Id,
CASE
WHEN LTRIM(RTRIM(AC)) = ' ' THEN AG
WHEN LOWER(AC) IS NOT NULL THEN LOWER(AC)
ELSE LOWER(AG)
END AS result,MaxDate,
FROM [DC_20160601] t
INNER JOIN ( SELECT Id, MAX(DateTime) AS MaxDate
FROM [DC_20160601]
GROUP BY Id) tm
ON t.Id = tm.Id AND t.DateTime = tm.MaxDate)
GROUP BY SUBSTRING_INDEX(`result`, ' ', 1)
You might try to extract everything before the first space and use this for grouping:
SUBSTRING_INDEX(result, ' ', 1)
Otherwise you need to maintain a lookup table to match multiple variations to a single result.
You can add the case statements as an outer query. Assuming that your query returns the Current Result that you posted, here is an example of the needed case statements:
select
case
when a.result = 'Wind' or a.result = 'Wind c' then 'Wind mobile'
else
case
when a.result = 'sqrim' or a.result = 'sqrim mob'
then 'Squirm mobile'
end
end as res,
sum(total)
from
(
SELECT result, COUNT(*) AS total from(
SELECT t.Id AS Id,
CASE
WHEN LTRIM(RTRIM(AC)) = ' ' THEN AG
WHEN LOWER(AC) IS NOT NULL THEN LOWER(AC)
ELSE LOWER(AG)
END AS result,MaxDate,
FROM [DC_20160601] t
INNER JOIN ( SELECT Id, MAX(DateTime) AS MaxDate
FROM [DC_20160601]
GROUP BY Id) tm
ON t.Id = tm.Id AND t.DateTime = tm.MaxDate)
GROUP BY result
) a
group by res
It would be best to have the values in the case statements specified in a lookup table and to get them from there or you can just add additional ones as case statements if needed but it's not ideal...
Hope this helps!

unknown column in IN/ALL/ANY subquery where clause

Problem:
I know it's documented in MYSQL DOCUMENTS That in where clause "alias" cannot be used since where clause is not populated yet. But i have to get the data matched from other table values in where clause (IN condition).
I have also read some similar kind of post but this one is quite different & big complex one. I couldn't make it working with my efforts of last 3 days.
It's showing error (excepted as per documentation)
UNKNOWN COLUMN "Ind_ID" in WHERE CLAUSE
I have to match similarly for FA_ID & PREFERRED_LOCATION_ID field
Select a.job_id, a.Employer_ID, a.Sub_user_id,
Date_format(a.creation_on,'%d-%m-%Y') as Created_date, a.Job_type,
a.Designation, a.Open_Positions, a.Job_Description, a.Min_age,
a.Max_age, a.min_exp, a.max_exp, a.Hide_Salary, a.company_name,
a.About_Company, a.Contact_person_name, a.Contact_No, a.Refresh_type,
a.Response_type,
(Select GROUP_CONCAT(DISTINCT g.Education ORDER BY pjedu.Education_ID
SEPARATOR ', ') user_education
from e_pj_edu pjedu
INNER JOIN education g ON FIND_IN_SET(g.Edu_ID, pjedu.Education_ID)
where a.job_id = pjedu.Job_ID
) as Education_ID,
(Select GROUP_CONCAT(DISTINCT h.FA_description ORDER BY uf.FA_ID
SEPARATOR ', ') FA
from e_pj_fa uf
INNER JOIN functional_area h ON FIND_IN_SET(h.FA_ID, uf.FA_ID)
where a.Job_ID = uf.Job_ID
) as FA_ID,
(Select GROUP_CONCAT(DISTINCT i.Industry_description ORDER BY
ui.Industry_ID SEPARATOR ', ') Industry_ID
from e_pj_industry ui
INNER JOIN industry i ON FIND_IN_SET(i.Industry_ID, ui.Industry_ID)
where a.Job_ID = ui.Job_ID
) as Ind_ID,
(Select GROUP_CONCAT(DISTINCT j.location_name ORDER BY
upl.Location_ID SEPARATOR ', ') Location_ID
from e_pj_locations upl
INNER JOIN locations j ON FIND_IN_SET(j.location_id, upl.Location_ID)
where a.Job_ID = upl.Job_ID
) as Preferred_Location_ID,
(Select GROUP_CONCAT(DISTINCT uk.Keyword_Name ORDER BY uk.Keyword_ID
SEPARATOR ', ') keyskills
from e_pj_keywords uk
where a.Job_ID = uk.Job_ID
) as Keyword_Name,
GROUP_CONCAT(DISTINCT cc.salary_description ORDER BY cc.salary_ID
SEPARATOR ', ') Min_salary,
GROUP_CONCAT(DISTINCT dd.salary_description ORDER BY dd.salary_ID
SEPARATOR ', ') Max_salary
from post_jobs a
INNER JOIN user_salary cc ON FIND_IN_SET(cc.salary_ID, a.Min_salary)
INNER JOIN user_salary dd ON FIND_IN_SET(dd.salary_ID, a.Max_salary)
WHERE a.Designation LIKE '%MIS%' or a.company_name LIKE '%MIS%'
And a.max_exp <= 9
And a.Max_salary<=110
And Ind_ID IN (10001,10002,10004)
And FA_ID IN(1001)
group by a.job_id
First thing that comes in my mind is just move your aliased where conditions to outer query, i.e.:
select * from (
Select a.job_id ....
WHERE a.Designation LIKE '%MIS%' or a.company_name LIKE '%MIS%'
And a.max_exp <= 9
And a.Max_salary<=110
group by a.job_id
) inner
where
Ind_ID IN (10001,10002,10004)
And FA_ID IN(1001)
GL!
Posting revised query which worked. May be this helps someone from wasting 3 days like me :-)
select * from (
Select a.job_id, a.Employer_ID, a.Sub_user_id, Date_format(a.creation_on,'%d-%m-%Y') as Created_date, a.Job_type, a.Designation, a.
Open_Positions, a.Job_Description, a.Min_age, a.Max_age, a.min_exp, a.max_exp, a.Hide_Salary, a.company_name, a.About_Company, a.Contact_person_name,
a.Contact_No, a.Refresh_type, a.Response_type,
(Select GROUP_CONCAT(DISTINCT g.Education ORDER BY pjedu.Education_ID SEPARATOR ', ') user_education
from e_pj_edu pjedu
INNER JOIN education g ON FIND_IN_SET(g.Edu_ID, pjedu.Education_ID)
where a.job_id = pjedu.Job_ID
) as Education_ID,
(Select GROUP_CONCAT(DISTINCT h.FA_description ORDER BY uf.FA_ID SEPARATOR ', ') FA
from e_pj_fa uf
INNER JOIN functional_area h ON FIND_IN_SET(h.FA_ID, uf.FA_ID)
where a.Job_ID = uf.Job_ID
) as FA_ID,
(Select GROUP_CONCAT(DISTINCT i.Industry_description ORDER BY ui.Industry_ID SEPARATOR ', ') Industry_ID
from e_pj_industry ui
INNER JOIN industry i ON FIND_IN_SET(i.Industry_ID, ui.Industry_ID)
where a.Job_ID = ui.Job_ID
) as Ind_ID,
(Select GROUP_CONCAT(DISTINCT j.location_name ORDER BY upl.Location_ID SEPARATOR ', ') Location_ID
from e_pj_locations upl
INNER JOIN locations j ON FIND_IN_SET(j.location_id, upl.Location_ID)
where a.Job_ID = upl.Job_ID
) as Preferred_Location_ID,
(Select GROUP_CONCAT(DISTINCT uk.Keyword_Name ORDER BY uk.Keyword_ID SEPARATOR ', ') keyskills
from e_pj_keywords uk
where a.Job_ID = uk.Job_ID
) as Keyword_Name,
GROUP_CONCAT(DISTINCT cc.salary_description ORDER BY cc.salary_ID SEPARATOR ', ') Min_salary,
GROUP_CONCAT(DISTINCT dd.salary_description ORDER BY dd.salary_ID SEPARATOR ', ') Max_salary
from post_jobs a
INNER JOIN user_salary cc ON FIND_IN_SET(cc.salary_ID, a.Min_salary)
INNER JOIN user_salary dd ON FIND_IN_SET(dd.salary_ID, a.Max_salary)
group by a.Job_id
) aa
WHERE Designation LIKE '%op%' or company_name LIKE '%op%'
And max_exp <= 15
And Max_salary<=120
and Ind_ID IN (10001,10002,10004,10003)
And FA_ID IN(1001,1002,1003)
group by Job_id

Mysql Subquery Work Slowly

I use view has subquery and concat in mysql. Normally, query works rapidly, but if query has subquery works very slowly.
This code is running quickly (approximate 1 seconds)
CREATE OR REPLACE VIEW ilceler AS (
SELECT I.id, I.modulid, I.id as icerikidsi,
MAX(IF(D.alanid=2,D.textkisa,NULL)) AS ilceadi,
MAX(IF(D.alanid=2,D.id,NULL)) AS ilceadi_i,
I.seo_description,
I.seo_h1,
I.seo_h2,
I.seo_h3,
I.seo_h4,
I.seo_imgalt,
I.seo_imgtitle,
I.seo_keywords,
I.seo_pagetitle,
I.seo_url,
I.seo_urltitle
FROM datalar as D LEFT JOIN icerikler as I ON D.icerikid=I.id WHERE D.modulid='3' GROUP BY D.icerikid ORDER BY sehiradi asc )
But this code is working very very slowly (approximate 20 seconds)
CREATE OR REPLACE VIEW ilceler AS (
SELECT I.id, I.modulid, I.id as icerikidsi,
MAX(IF(D.alanid=2,D.textkisa,NULL)) AS ilceadi,
MAX(IF(D.alanid=2,D.id,NULL)) AS ilceadi_i,
( SELECT CONVERT ( GROUP_CONCAT(D2.id SEPARATOR ' ₋ ' ) USING UTF8 )FROM datalar as D1
LEFT JOIN datalar as D2 ON D1.iliskialanid=D2.id WHERE D1.modulid='3' AND D1.alanid='3' AND D1.icerikid=icerikidsi ) as sehiradi_a ,
( SELECT GROUP_CONCAT(iliskiid SEPARATOR ' ₋ ') FROM datalar WHERE alanid='3' AND modulid='3' AND icerikid=icerikidsi ) as sehiradi_i,
( SELECT GROUP_CONCAT(D2.textkisa SEPARATOR ' ₋ ' ) FROM datalar as D1 LEFT JOIN datalar as D2 ON D1.iliskialanid=D2.id
WHERE D1.modulid='3' AND D1.alanid='3' AND D1.icerikid=icerikidsi ) as sehiradi ,
I.seo_description,
I.seo_h1,
I.seo_h2,
I.seo_h3,
I.seo_h4,
I.seo_imgalt,
I.seo_imgtitle,
I.seo_keywords,
I.seo_pagetitle,
I.seo_url,
I.seo_urltitle
FROM datalar as D LEFT JOIN icerikler as I ON D.icerikid=I.id WHERE D.modulid='3' GROUP BY D.icerikid ORDER BY sehiradi asc )
Why? Where do I make mistake?
I am waiting for your help.
Your sub queries rely on the values of the select, hence each of those 3 sub queries needs to be performed for each returned row. With a small number of rows this isn't an issue but with lots of rows this can rapidly add up.
Normal solution is to join against the sub query (hence it is done once for all rows and you just join the results).
For example:-
SELECT I.id,
I.modulid,
I.id as icerikidsi,
MAX(IF(D.alanid=2,D.textkisa,NULL)) AS ilceadi,
MAX(IF(D.alanid=2,D.id,NULL)) AS ilceadi_i,
sub1.sehiradi_a ,
sub2.sehiradi_i,
sub1.sehiradi ,
I.seo_description,
I.seo_h1,
I.seo_h2,
I.seo_h3,
I.seo_h4,
I.seo_imgalt,
I.seo_imgtitle,
I.seo_keywords,
I.seo_pagetitle,
I.seo_url,
I.seo_urltitle
FROM datalar as D
LEFT JOIN icerikler as I ON D.icerikid=I.id
LEFT OUTER JOIN
(
SELECT D1.icerikid, CONVERT ( GROUP_CONCAT(D2.id SEPARATOR ' ₋ ' ) USING UTF8 ) AS sehiradi_a, GROUP_CONCAT(D2.textkisa SEPARATOR ' ₋ ' ) AS sehiradi
FROM datalar as D1
LEFT JOIN datalar as D2 ON D1.iliskialanid=D2.id
WHERE D1.modulid='3'
AND D1.alanid='3'
GROUP BY D1.icerikid
) sub1
ON sub1.icerikid = I.id
LEFT OUTER JOIN
(
SELECT icerikid, GROUP_CONCAT(iliskiid SEPARATOR ' ₋ ') AS sehiradi_i
FROM datalar
WHERE alanid='3'
AND modulid='3'
GROUP BY icerikid
) sub2
ON sub2.icerikid = I.id
WHERE D.modulid='3'
GROUP BY D.icerikid
ORDER BY sehiradi asc
Or depending on your actual database design you might be able to simplify it to
SELECT I.id,
I.modulid,
I.id as icerikidsi,
MAX(IF(D.alanid=2,D.textkisa,NULL)) AS ilceadi,
MAX(IF(D.alanid=2,D.id,NULL)) AS ilceadi_i,
sub1.sehiradi_a ,
sub1.sehiradi_i,
sub1.sehiradi ,
I.seo_description,
I.seo_h1,
I.seo_h2,
I.seo_h3,
I.seo_h4,
I.seo_imgalt,
I.seo_imgtitle,
I.seo_keywords,
I.seo_pagetitle,
I.seo_url,
I.seo_urltitle
FROM datalar as D
LEFT JOIN icerikler as I ON D.icerikid=I.id
LEFT OUTER JOIN
(
SELECT D1.icerikid,
CONVERT ( GROUP_CONCAT(D2.id SEPARATOR ' ₋ ' ) USING UTF8 ) AS sehiradi_a,
GROUP_CONCAT(D2.textkisa SEPARATOR ' ₋ ' ) AS sehiradi,
GROUP_CONCAT(DISTINCT D1.iliskiid SEPARATOR ' ₋ ') AS sehiradi_i
FROM datalar as D1
LEFT JOIN datalar as D2 ON D1.iliskialanid=D2.id
WHERE D1.modulid='3'
AND D1.alanid='3'
GROUP BY D1.icerikid
) sub1
ON sub1.icerikid = I.id
WHERE D.modulid='3'
GROUP BY D.icerikid
ORDER BY sehiradi asc
However there is a minor issue here. In MySQL a view cannot contain a FROM that takes data from a sub query. As such to use this syntax in your view you would need to split the sub queries off into their own views. Then you could join against the view rather than the sub query.

SQL Joins to Get Monthly Total Wages from Three Tables

I need to get empolyees info from employees table, and their total wages from two different tables.
The SQL is approximately like this, but I don't really know how to use joins to do this:
CONCAT(first_name, ' ', last_name) from employees as e
Sum(hours*pay) where date is "THIS MONTH" and employee_id = e.id from taxed_work
Sum(hours*pay) where date is "THIS MONTH" and employee_id = e.id from nontaxed_work
I am not sure how to join these together properly. I don't want to see any of the employees that have not done either kind of work for the month, only those who have. I'm using mysql and will put the data in a table with php
If anyone could tell me how to do the "THIS MONTH" part that would be cool too. Just being lazy on that part, but figured while I was here...
Thanks for the help!
You could use correlated subqueries:
select concat(first_name, ' ', last_name)
, (
select sum(hours*pay)
from taxed_work tw
where tw.employee_id = e.id
and year(tw.date) = year(now())
and month(tw.date) = month(now())
)
, (
select sum(hours*pay)
from nontaxed_work ntw
where ntw.employee_id = e.id
and year(ntw.date) = year(now())
and month(ntw.date) = month(now())
)
from employees e
You can calculate their totals inside subquery.
SELECT a.id ,
CONCAT(first_name, ' ', last_name) FullName,
b.totalTax,
c.totalNonTax,
FROM employees a
LEFT JOIN
(
SELECT employee_id, Sum(hours*pay) totalTax
FROM taxed_work
WHERE DATE_FORMAT(`date`,'%c') = DATE_FORMAT(GETDATE(),'%c')
GROUP BY employee_id
) b ON b.employee_id = a.id
LEFT JOIN
(
SELECT employee_id, Sum(hours*pay) totalTax
FROM nontaxed_work
WHERE DATE_FORMAT(`date`,'%c') = DATE_FORMAT(GETDATE(),'%c')
GROUP BY employee_id
) c ON c.employee_id = a.id
Try this query.
select
CONCAT(first_name, ' ', last_name) as employee_name,
sum(case when t.this_date = 'this_month' then t.hours*t.pay else 0 end),
sum(case when n.this_date = 'this_month' then t.hours*t.pay else 0 end)
from employees e
left join taxed_work t on e.id = t.employee_id
left join nontaxed_work n on e.id = n.employee_id
group by (first_name, ' ', last_name)
Please replace the t.this_date and n.this_date fields with actual field names as I am not aware of the exact table structure. Also, replace the "this_month" value as per your need.