SQL query to combine total of two fields - mysql

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!

Related

Group by Specific month in SQL. For example group by month "november"

basically there are three tables with the following schema:
we are supposed to get average humidity of the states and country where month is November. it shows the following error where (state_weather_stats.record_date) shows following error:
ERROR 1054 (42S22) at line 8: Unknown column
'state_weather_stats.record_date' in 'HAVING clause'
if month() is supposed to return a number between 1 and 12, what is the error in the following code any help would be greatly appreciated.
SET sql_mode = 'PIPES_AS_CONCAT';
SELECT state.name || ' ' || country.name || ' ' ||
AVG(state_weather_stats.humidity) || ' ' || CASE
WHEN AVG(state_weather_stats.temperature) < 20 then
'COLD'
WHEN AVG(state_weather_stats.temperature) < 30 then
'WARM'
ELSE
'HOT'
END AS temp
FROM country
INNER JOIN state
ON country.id = state.country_id
INNER JOIN state_weather_stats
ON state.id = state_weather_stats.state_id
GROUP BY month(state_weather_stats.record_date)
HAVING month(state_weather_stats.record_date) = 11
ORDER BY AVG(state_weather_stats.humidity) desc, state.name asc;
I would recommend to separate the creation of your string with the query that retrieves your averages.
You can:
apply your JOIN operations first
select your preferred month inside the condition of the INNER JOIN
aggregate on the fields you are selecting ("s.name" and "c.name")
use CONCAT_WS to concatenate strings of your choice with the delimiter given as first input.
WITH cte AS (
SELECT s.name AS state_name,
c.name AS country_name,
AVG(w.humidity) AS avg_humidity,
AVG(w.temperature) AS avg_temperature
FROM country c
INNER JOIN state s
ON c.id = s.country_id
INNER JOIN state_weather_stats w
ON s.id = w.state_id
AND MONTH(w.record_date) = 11
GROUP BY s.name,
c.name
)
SELECT CONCAT_WS(' ', state_name,
country_name,
avg_humidity,
CASE WHEN avg_temperature < 20 THEN 'COLD'
WHEN avg_temperature < 30 THEN 'WARM'
ELSE 'HOT' END) AS temp
FROM cte

MySQL with multiple SELECT and GROUP BY

I have a problem with my database in mysql. I would like to have a table from my database with date, pat, dureeP, dureeC but this function doesn't GROUP BY :
select *
from (SELECT date_format(p.date, "%Y-%m") AS date
,p.pat
,AVG(a) AS dureeP
FROM timing as t, patient as p
WHERE t.id_p = p.id_p
AND t.pos=6
AND t.heure_fin IS NOT NULL
GROUP BY p.pat, MONTH(p.date), YEAR(p.datede)
) as T1,
(SELECT AVG(b) AS dureeC
FROM timing as t, patient as p
WHERE t.id_p = p.id_p
AND t.pos=3
AND t.heure_fin IS NOT NULL
GROUP BY p.pathologie, MONTH(p.date), YEAR(p.date)
) as T2
With one SELECT I can have what I want but with multiple SELECT I can Group By.
Do you have an idea?
Thank you
To simplify your query you might be able to use "conditional aggregates" which basically means placing a case expression inside an aggregate function
SELECT
p.pathologie
, MONTH(p.date)
, YEAR(p.date)
, AVG(CASE WHEN t.pos = 3 THEN b END) AS dureeC
, AVG(CASE WHEN t.pos = 6 THEN a END) AS dureeP
FROM timing AS t
INNER JOIN patient AS p ON t.id_p = p.id_p
WHERE t.heure_fin IS NOT NULL
GROUP BY
p.pathologie
, MONTH(p.date)
, YEAR(p.date)

IF / CASE statement in SQL

I'm really struggling to find an answer to this issue. I want to write an if or case statement that changes a value in another column. If column 'check' is 0 then column 'points' should be 0 as well.
SELECT club_name, COALESCE(club_winner,0) AS 'check', COUNT(*) AS points,
CASE
WHEN check = '0'
THEN points = '0'
ELSE check
END as Saleable
FROM clubs c
LEFT JOIN club_results cr ON c.club_id = cr.club_winner
GROUP BY club_name ORDER BY points DESC
You can't "SET" columns in a case statement, you can return the value. Think of the case statement as a variable column. Return '0' AS Saleable (Or whatever column you wish to name).
SELECT club_name, COALESCE(club_winner,0) AS 'check', COUNT(*) AS points,
CASE
WHEN COALESCE(club_winner,0) = 0
THEN 0
ELSE COUNT(*)
END AS points_or_0_if_check_is_0
FROM clubs c
LEFT JOIN club_results cr ON c.club_id = cr.club_winner
GROUP BY club_name ORDER BY points_or_0_if_check_is_0 DESC
You can select to count only lines matching your left join like so:
SELECT
club_name,
COUNT(
CASE WHEN
club_winner IS NOT NULL
THEN
CR.id
ELSE
NULL
END
) AS `points`
FROM
clubs C
LEFT JOIN
club_results CR ON C.club_id = CR.club_winner
GROUP BY
C.club_id
ORDER BY
points DESC

MySql Group by with Pivot

I am having a table in mysql (say studentinfo).
SELECT * FROM StudentInfo;
I want the following output without using any extra or temporary table. (May be using group by and pivot)
You need to create a pivot table, here is a link with lots of good examples.
Essentially, your just gonna do something like this
SELECT Rollnumber,
property
CASE WHEN Property="Name" then Property end as Name,
CASE WHEN Property="Year" then Property end as Year,
CASE WHEN Property="City" then Property end as City,
FROM whatever_table
GROUP BY Rollnumber
You can modify this however you want, to get the results you desire.
This should do what you want:
select si.Rollnumber,
max(case when si.Property = 'Name' then si.Value end) as Name,
max(case when si.Property = 'Year' then si.Value end) as Year,
max(case when si.Property = 'City' then si.Value end) as City
from StudentInfo si
group by si.Rollnumber;
Try below:
select * from (SELECT A.Rollnumber,if(A.Property='Name',Value,
(select B.Value from StudentInfo B where B.Property='Name' and B.Rollnumber=A.Rollnumber LIMIT 1)) as Name,
if(Property='Year',Value,
(select B.Value from StudentInfo B where B.Property='Year' and B.Rollnumber=A.Rollnumber LIMIT 1)) as Year,
if(Property='City',Value,
(select B.Value from StudentInfo B where B.Property='City' and B.Rollnumber=A.Rollnumber LIMIT 1))
as City
FROM StudentInfo A) Temp group by Rollnumber
SELECT
name.rollnumber,
name.value AS name,
year.value AS year,
city.value AS city
FROM
StudentInfo name
INNER JOIN StudentInfo year ON name.rollnumber = year.rollnumber
INNER JOIN StudentInfo city ON name.rollnumber = city.rollnumber
WHERE
name.property = 'name' AND
year.property = 'year' AND
city.property = 'city' AND

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.