The stucture of table day and report is as below.
day
id day
1 sunday
2 monday
3 tuesday
4 thursday
5 friday
6 saturday
report
id dta day ndx
1 10 1 1
2 15 2 1
3 14 3 1
4 15 4 1
5 12 5 1
6 11 6 1
7 55 1 2
8 23 2 2
9 10 3 2
10 19 4 2
Need to be group by report.ndx, so data would be managed as index wise
ndx-1, sunday-10, monday-15, tuesday-14, thursday-15, friday-12, saturday-11
ndx-2, sunday-55, monday-23, tuesday-10, thursday-19
Sql Syntax with group by
SELECT report.ndx AS ndx, GROUP_CONCAT(day.day,'-',report.dta) AS data
FROM report
LEFT JOIN day ON day.id = report.day
GROUP BY report.ndx
But requirment is placing null value if day is not in report table. For example
ndx-2, sunday-55, monday-23, tuesday-10, thursday-19, friday-0, saturday-0
So what I tried with coalesce
SELECT report.ndx AS ndx, GROUP_CONCAT(day.day,'-',COALESCE(report.dta),'0') AS data
FROM report
LEFT JOIN day ON day.id = report.day
GROUP BY report.ndx
But I think, as report is primary in SQL JOIN Statement, so coalesce is useless to use setting null value.
I tried with case when
SELECT GROUP_CONCAT(DISTINCT CASE
WHEN day.id=report.day
THEN CONCAT(day.day,'-',report.dta)
ELSE CONCAT(day.day,'-',0) END) AS data
FROM report
LEFT JOIN day ON 1=1
GROUP BY report.ndx
But it prints once null value with day and again value with matched day in same index. For example
sunday-10, sunday-0
You have 2 mistakes:
COALESCE requires at least 2 arguments to be meaningful but you have provided only 1 argument report.dta
you are joining the tables in the wrong order. If you want to get all days from table day even if no record in table report references that day - then you should put day in the FROM clause and then join report on the left
You can try something like this:
SELECT ndx, GROUP_CONCAT(CONCAT(day,'-',dta))
FROM
(SELECT d.id, d.day, IFNULL(dta,0) dta, IFNULL(ndx,1) ndx
FROM day d LEFT JOIN report r
ON d.id=r.day AND ndx=1
UNION ALL
SELECT d.id, d.day, IFNULL(dta,0) dta, IFNULL(ndx,2) ndx
FROM day d LEFT JOIN report r
ON d.id=r.day AND ndx=2) A
GROUP BY ndx
Make a LEFT JOIN query between day and report tables.
Separate the queries by ndx value and UNION ALL it.
Replace NULL values using IFNULL(dta,0) for dta and IFNULL(ndx,[value]); where the [value] is whatever value of ndx in WHERE.
Turn that query to become sub-query.
Type in the SELECT ndx, GROUP_CONCAT(... condition then GROUP BY ndx.
Demo fiddle
Related
I have two tables namely "appointment" and "skills_data".
Structure of appointment table is:
id_ap || ap_meet_date || id_skill || ap_status.
And the value of ap_status are complete, confirm, cancel and missed.
And the skills_data table contains two columns namely:
id_skill || skill
I want to get the count of total number of appointments for each of these conditions
ap_status = ('complete' and 'confirm'),
ap_status = 'cancel' and
ap_status = 'missed'
GROUP BY id_skill and year and
order by year DESC
I tried this query which only gives me count of one condition but I want to get other two based on group by and order by clauses as mentioned.
If there is no record(for example: zero appointments missed in 2018 for a skill) matching for certain conditions, then it should display the output value 0 for zero count.
Could someone please suggest me with a query whether I should implement multiple select query or CASE clause to achieve my expected results. I have lot of records in appointment table and want a efficient way to query my records. Thank you!
SELECT a.id_skill, YEAR(a.ap_meet_date) As year, s.skill,COUNT(*) as count_comp_conf
FROM appointment a,skills_data s WHERE a.id_skill=s.id_skill and a.ap_status IN ('complete', 'confirm')
GROUP BY `id_skill`, `year`
ORDER BY `YEAR` DESC
Output from my query:
id_skill | year | skill | count_comp_conf
-----------------------------------------
1 2018 A 20
2 2018 B 15
1 2019 A 10
2 2019 B 12
3 2019 C 10
My expected output should be like this:
id_skill | year | skill | count_comp_conf | count_cancel | count_missed
------------------------------------------------------------------------
1 2018 A 20 5 1
2 2018 B 15 8 0
1 2019 A 10 4 1
2 2019 B 12 0 5
3 2019 C 10 2 2
You can use conditional aggregation using case when expression
SELECT a.id_skill, YEAR(a.ap_meet_date) As year, s.skill,
COUNT(case when a.ap_status IN ('complete', 'confirm') then 1 end) as count_comp_conf,
COUNT(case when a.ap_status = 'cancel' then 1 end) as count_cancel,
COUNT(case when a.ap_status = 'missed' then 1 end) as count_missed
FROM appointment a inner join skills_data s on a.id_skill=s.id_skill
GROUP BY `id_skill`, `year`
ORDER BY `YEAR` DESC
SELECT a.id_skill,
YEAR(a.ap_meet_date) As year,
s.skill,
SUM(IF(a.ap_status IN ('complete', 'confirm'),1,0)) AS count_comp_conf,
SUM(IF(a.ap_status='cancel',1,0)) AS count_cancel,
SUM(IF(a.ap_status='missed',1,0)) AS count_missed
FROM appointment a,skills_data s WHERE a.id_skill=s.id_skill
GROUP BY `id_skill`, `year`
ORDER BY `YEAR` DESC;
Please try to use if condition along with sum.
With below query you will get output.
select id_skill ,
year ,
skill ,
count_comp_conf ,
count_cancel ,
count_missed ( select id_skill, year, skill, if ap_status ='Completed' then count_comp_conf+1, elseif ap_status ='cancelled' then count_cancel +1 else count_missed+1
from appointment a join skills_data s on (a.id_skill = s.id_skill) group by id_skill, year) group by id_skill,year
order by year desc;
I have qualified risks with description and creation date, who are attached to subcategory of risks this last ones are attached to category of risks, each risk has a name like 'Risk_1' , my aim is to count the number of risks by month and risk category including zero.
I have this request :
SELECT DISTINCT risk_names.type as risk_name, MONTH(risk.creation_date) as month, count(risk.id) as number FROM risk As risk , risk_category
JOIN (
SELECT risk_category.name as type
FROM
risk_category
) as risk_names on risk_names.type = risk_category.name
where risk.creation_date >= (NOW()-INTERVAL 3 MONTH) GROUP BY MONTH(risk.creation_date), risk_names.type;
Who return this result :
Risk_name month number
---------------------------------
Risk_1 1 10 ---> instead 8
Risk_2 1 10 ---> instead 1
Risk_3 1 10 ---> instead 1
Risk_1 2 12 ......
Risk_2 2 12
Risk_3 2 12
Risk_1 12 4
Risk_2 12 4
Risk_3 12 4
As you can see the number returned is the total for each month , but my aim is to get total for each distinct risk.
Can you help me . thanks
The comma in your FROM is doing a CROSS JOIN. A Cartesian product is unnecessary and throws all the counts off.
I suspect you want something like this:
SELECT rc.type as risk_name, MONTH(r.creation_date) as month,
count(r.id) as number
FROM risk_category rc LEFT JOIN
risk r
ON r.?? = rc.??
where risk.creation_date >= (NOW()-INTERVAL 3 MONTH)
GROUP BY rc.type, MONTH(r.creation_date);
I don't know what the JOIN criterion is between risk and risk_category.
Then try using distinct keuword with count() like count(distinct risk.id) as number instead
Gosh, it must be so simple but I'm struggling with this 'filling out missing data' issue.
I have a table that has the following columns with some inserted data.
TABLE
year month payment
2014 3 100
2014 5 800
2014 9 200
And what I want from this table is to have a full range of months with its payment value from 2014.
Month Payment
1 0
2 0
3 100
4 0
5 800
...
12 0
I tried using IFNULL in select but failed so bad... and search results from stackoverflow usually join two or more tables to manipulate information. What would be the fastest and best solution to solve this problem?
For missing months you can have a union query with all months and join with your table
SELECT
t1.`year`,
t.`month`,
coalesce(t1.payment,0) payment
FROM
(SELECT 1 AS `month`
UNION
SELECT 2 AS `month`
UNION
....
SELECT 12 AS `month`
) AS t
LEFT JOIN your_table t1 on(t.`month` = t1.`month`)
WHERE ....
Fiddle Demo
I have three tables and am trying to get info from two and then perform a calculation on the third and display all the results in one query.
The (simplified) tables are:
table: employee_work
employee_id name
1 Joe
2 Bob
3 Jane
4 Michelle
table: carryover
employee_id days
1 5
2 10
3 3
table: timeoff
employee_id time_off_type days
1 Carryover 2
1 Leave 3
1 Carryover 1
2 Sick 4
2 Carryover 4
3 Leave 1
4 Sickness 4
The results I would like are:
employee_id, carryover.days, timeoff.days
1 5 3
2 10 4
3 3 0
However when I run the query, whilst I get the correct values in columns 1 and 2, I get the same number repeated in the third column for all entries.
Here is my query:
Select
employee_work.employee_id,
carryover.carryover,
(SELECT SUM(days) FROM timeoff WHERE timeoff.time_off_type = 'Carryover'
AND timeoff.start_date>='2013-01-01') AS taken
From
carryover Left Join
employee_work On employee_work.employee_id = carryover.employee_id Left Join
timeoff On employee_work.employee_id = timeoff.employee_id Left Join
Where
carryover.carryover > 0
Group By
employee_work.employee_id
I have tried to group by in the sub query but I then get told "Subquery returns more than one row" - how can I ensure that the sub query is respecting the join so it only looks at each employee at a time so I get my desired results?
The answer to your question is to use a correlated subquery. You don't need to mention the timeoff table twice in this case:
Select
employee_work.employee_id,
carryover.carryover,
(SELECT SUM(days)
FROM timeoff
WHERE timeoff.time_off_type = 'Carryover' and
timeoff.start_date>='2013-01-01' and
timeoff.employee_id = employee_work.employee_id
) AS taken
From
carryover Left Join
employee_work On employee_work.employee_id = carryover.employee_id
Where
carryover.carryover > 0
Group By
employee_work.employee_id;
An alternative structure is to do the grouping for all employees in the from clause. You can also remove the employee_work table, because it does not seem to be being used. (You can use carryover.employee_id for the id.)
Select co.employee_id, co.carryover, et.taken
From carryover c Left Join
(SELECT employee_id, SUM(days) as taken
FROM timeoff
WHERE timeoff.time_off_type = 'Carryover' and
timeoff.start_date>='2013-01-01'
) et
on co.employee_id = et.employee_id
Where c.carryover > 0;
I don't think the group by is necessary. If it is, then you should probably have an aggregation function in the original query.
I have a table with columns similar to below , but with about 30 date columns and 500+ records
id | forcast_date | actual_date
1 10/01/2013 12/01/2013
2 03/01/2013 06/01/2013
3 05/01/2013 05/01/2013
4 10/01/2013 09/01/2013
and what I need to do is get a query with output similar to
week_no | count_forcast | count_actual
1 4 6
2 5 7
3 2 1
etc
My query is
SELECT weekofyear(forcast_date) as week_num,
COUNT(forcast_date) AS count_forcast ,
COUNT(actual_date) AS count_actual
FROM
table
GROUP BY
week_num
but what I am getting is the forcast_date counts repeated in each column, i.e.
week_no | count_forcast | count_actual
1 4 4
2 5 5
3 2 2
Can any one please tell me the best way to formulate the query to get what I need??
Thanks
try:
SELECT weekofyear(forcast_date) AS week_forcast,
COUNT(forcast_date) AS count_forcast, t2.count_actual
FROM
t t1 LEFT JOIN (
SELECT weekofyear(actual_date) AS week_actual,
COUNT(forcast_date) AS count_actual
FROM t
GROUP BY weekOfYear(actual_date)
) AS t2 ON weekofyear(forcast_date)=week_actual
GROUP BY
weekofyear(forcast_date), t2.count_actual
sqlFiddle
You have to write about 30 (your date columns) left join, and the requirement is that your first date column shouldn'd have empty week (with a count of 0) or the joins will miss.
Try:
SELECT WeekInYear, ForecastCount, ActualCount
FROM ( SELECT A.WeekInYear, A.ForecastCount, B.ActualCount FROM (
SELECT weekofyear(forecast_date) as WeekInYear,
COUNT(forecast_date) as ForecastCount, 0 as ActualCount
FROM TableWeeks
GROUP BY weekofyear(forecast_date)
) A
INNER JOIN
( SELECT * FROM
(
SELECT weekofyear(forecast_date) as WeekInYear,
0 as ForecastCount, COUNT(actual_date) as ActualCount
FROM TableWeeks
GROUP BY weekofyear(actual_date)
) ActualTable ) B
ON A.WeekInYear = B.WeekInYear)
AllTable
GROUP BY WeekInYear;
Here's my Fiddle Demo
Just in case someone else comes along with the same question:
Instead of trying to use some amazing query, I ended up creating an array of date_columns_names and a loop in the program that was calling this query, and for each date_column_name, performing teh asme query. It is a bit slower, but it does work