How to SUM result both SUMs SQL? - mysql

Using this query I try to sum result of both SUM function:
select
DAY(created_at) AS day,
SUM(if(status = '1', 1, 0)) AS result,
SUM(if(status = '2', 1, 0)) AS noresult,
SUM(result + noresult)
from `clients` where `doctor_id` = 2 and MONTH(created_at) = MONTH(CURRENT_TIMESTAMP) group by `day`
I try to do that in this line:
SUM(result + noresult)

Try this:
select
DAY(created_at) AS day,
SUM(if(status = '1', 1, 0)) AS result,
SUM(if(status = '2', 1, 0)) AS noresult,
SUM(if(status in ('1', '2'), 1, 0))
from `clients`
where `doctor_id` = 2 and MONTH(created_at) = MONTH(CURRENT_TIMESTAMP)
group by `day`

You can't use alias in select columns name you must repeat the code
select
DAY(created_at) AS day,
SUM(if(status = '1', 1, 0)) AS result,
SUM(if(status = '2', 1, 0)) AS noresult,
SUM(if(status = '1', 1, 0)) + SUM(if(status = '2', 1, 0)) AS all_result
from `clients` where `doctor_id` = 2 and MONTH(created_at) = MONTH(CURRENT_TIMESTAMP) group by `day`
you must repeat the code because the different SQL clause are processed in a specific order (first from then where then select and and group by .... etc.. ) so at the moment of the select parsing the alias are not available to the sql engine

As several other people have stated, you cannot use aliases in your select statement. However, to keep it cleaner, you could combine both conditions rather than summing both SUM fields.
select
DAY(created_at) AS day,
SUM(if(status = '1', 1, 0)) AS result,
SUM(if(status = '2', 1, 0)) AS noresult,
SUM(if(status = '1' OR status = '2', 1, 0)) AS newcolumn
from `clients` where `doctor_id` = 2 and MONTH(created_at) = MONTH(CURRENT_TIMESTAMP) group by `day`

Related

How to group output and create columns from results [duplicate]

I have a simple query that produces the below results:
SELECT month,transporttype,count(transporttype) as loads
from deliveries
group by month,transporttype
I would like to transpose the rows into columns.
I understand mysql does not have pivot functions so a union is required but not 100% sure.
Thanks in advance for the help.
You can do it with a crosstab like this -
SELECT
`year`,
`month`,
SUM(IF(`transporttype` = 'inbound', 1, 0)) AS `inbound`,
SUM(IF(`transporttype` = 'LocalPMB', 1, 0)) AS `LocalPMB`,
SUM(IF(`transporttype` = 'Long Distance', 1, 0)) AS `Long Distance`,
SUM(IF(`transporttype` = 'shuttle', 1, 0)) AS `shuttle`,
SUM(IF(`transporttype` = 'export', 1, 0)) AS `export`,
SUM(IF(`transporttype` = 'Extrusions-LongDistance', 1, 0)) AS `Extrusions-LongDistance`,
SUM(IF(`transporttype` = 'Extrusions-Shuttle', 1, 0)) AS `Extrusions-Shuttle`
FROM `deliveries`
GROUP BY `year`, `month`
On a different note, you should move transporttype values to a lookup table and have transporttype_id in this table.

SQL: count and sum based on conditions from the related table

I have two tables;
countries(id, name, region);
1, 'UK', '1';
2, 'USA', '1';
3, 'AUSTRALIA', '1';
4, 'CHINA', '0';
5, 'INDIA', '0';
6, 'SRI LANKA', '0' ;
and
tickets(id, country_id, issued_date, holder, gender, fee, canceled);
100, 2, 2017-08-15, 'Person 1', 'M', 200, '1';
101, 2, 2017-08-15, 'Person 2', 'M', 200, '0';
103, 3, 2017-08-15, 'Person 3', 'M', 200, '0';
104, 5, 2017-08-16, 'Person 1', 'M', 200, '0';
105, 6, 2017-08-16, 'Person 1', 'M', 200, '0';
106, 1, 2017-08-17, 'Person 1', 'M', 200, '0';
107, 3, 2017-08-18, 'Person 1', 'M', 200, '1';
108, 4, 2017-08-18, 'Person 1', 'M', 200, '0';
I want to group all the tickets based on issued_date with some aggregates fields to generate the summary. Here is my query:-
SELECT
issued_date,
COUNT(*) as total_tickets,
COUNT(CASE WHEN canceled = '0' THEN 1 ELSE NULL END) as issued_tickets,
SUM(CASE WHEN canceled = '0' THEN fee ELSE NULL END) as total_amount
FROM tickets
GROUP BY issued_date;
But, how to use COUNT and SUM for related table countries? For example, I want to show how many tickets were sold on a date (2017-08-15) from a country having region = '1'.
I tried the following, but the results are not correct for region_1 field
SELECT
issued_date,
COUNT(*) as total_tickets,
COUNT(CASE WHEN canceled = '0' THEN 1 ELSE NULL END) as issued_tickets,SUM(CASE WHEN canceled = '0' THEN fee ELSE NULL END) as total_amount,
(SELECT COUNT(countries.id) FROM countries WHERE countries.id = tickets.country_id && countries.region = '1') as region_1
FROM tickets
GROUP BY issued_date;
I would use a derived table that is grouped on issue_date, country_id and region and use that derived table in an inner join.
SELECT issued_date
,COUNT(*) AS total_tickets
,COUNT(CASE WHEN canceled = '0' THEN 1 ELSE NULL END) AS issued_tickets
,SUM(CASE WHEN canceled = '0' THEN fee ELSE NULL END) AS total_amount
,tickets_by_region.total_region_1_tickets
FROM tickets
INNER JOIN (
SELECT issued_date
,country_id
,countries.region
,COUNT(*) AS total_region_1_tickets
FROM tickets
INNER JOIN countries ON (countries.id = tickets.country_id)
GROUP BY issued_date
,countries.country_id
,countries.region
) tickets_by_region ON (
tickets_by_region.issued_date = tickets.issued_date
AND tickets_by_region.country_id = tickets.country_id
AND tickets_by_region.region = '1'
) AS region_1
GROUP BY issued_date;
HTH.
You probably need to use INNER JOIN and GROUP BY with HAVING which allow append next table on related keys and add to additional summary or counts you need to use them like sub-query because they need to work with no filtered data.
Approach is prepare data in sub-query and then JOIN the filtered data
to your main table which can do final filtering for final result.
SQL can looks like bellow (tested on local)
SELECT t1.issued_date, COUNT(t1.id) as sum_tickets, t2.region, t3.total_tickets
FROM tickets t1
LEFT JOIN (SELECT id, COUNT(id) as total_tickets FROM tickets) t3 ON t3.id = t1.id
INNER JOIN countries t2 ON t2.id = t1.country_id
GROUP BY t1.issued_date
HAVING (t2.region = '1')
Output is
issued_date, sum_tickets, region, total_tickets
2017-08-15, 3, 1, 8
2017-08-17, 1, 1, null
2017-08-18, 2, 1, null
You can add more conditions to HAVING in query.
I would just use conditional aggregation with a JOIN:
SELECT t.issued_date, COUNT(*) as total_tickets,
SUM(t.canceled = 0) as issued_tickets,
SUM(CASE WHEN t.canceled = 0 THEN t.fee END) as total_amount,
SUM(c.region = 1) as num_region_1
FROM tickets t JOIN
countries c
ON t.country_id = c.id
GROUP BY t.issued_date;

SQL Get most frequent value from a column based on a condition

This query
SELECT
PlayerID, HeroTypeID, HeroTypeIDCount, Wins / (Losses + Wins) AS WinRate, Wins, Losses
FROM (
SELECT E.PlayerID AS PlayerID,
FK_HeroTypeID AS HeroTypeID,
COUNT(FK_HeroTypeID) AS HeroTypeIDCount,
SUM(CASE WHEN D.Result = 'LOSS' THEN 1 ELSE 0 END) AS Losses,
SUM(CASE WHEN D.Result = 'WIN' THEN 1 ELSE 0 END) AS Wins
FROM GamePlayerDetail D
JOIN Player E
ON D.FK_PlayerID = E.PlayerID
JOIN Game I
ON D.FK_GameID = I.GameID
WHERE PlayedDate BETWEEN DATE_SUB(CURDATE(), INTERVAL 7 DAY) AND CURDATE()
GROUP BY E.PlayerID, FK_HeroTypeID
) AS T
ORDER BY PlayerID
produces the following result:
# PlayerID, HeroTypeID, HeroTypeIDCount, WinRate, Wins, Losses
'1', '11', '1', '1.0000', '1', '0'
'1', '13', '3', '0.3333', '1', '2'
'1', '24', '5', '0.8000', '4', '1'
'1', '27', '1', '1.0000', '1', '0'
'2', '28', '1', '0.0000', '0', '1'
'2', '6', '1', '0.0000', '0', '1'
'2', '30', '1', '0.0000', '0', '1'
'2', '7', '1', '1.0000', '1', '0'
What I'd like to do is get the most frequent FK_HeroTypeID (which is also highest value of HeroTypeIDCount) per PlayerID, but in case of ties, the highest winrate should take precedence. Here's an example of what I'd like to get:
PlayerID, HeroTypeID, HeroTypeIDCount, WinRate, Wins, Losses
1, 24, 5, 0.8000, 4, 1
2, 7, 1, 1.0000, 1, 0
How should you write a query like this?
Edit:
Ok, here's a simple Create/Insert table for the produced result.
http://sqlfiddle.com/#!9/d644a
SELECT playerid
, herotypeid
, herotypeidcount
, winrate
, wins
, losses
FROM
( SELECT *
, CASE WHEN #prev=playerid THEN #i:=#i+1 ELSE #i:=1 END rank
, #prev:=playerid prev
FROM table1
, (SELECT #prev:=null,#i:=0) vars
ORDER
BY herotypeidcount DESC
, winrate DESC
) x
WHERE rank = 1;
Here's a 'hack' solution. It works, but really shouldn't be relied upon...
SELECT *
FROM
( SELECT *
FROM table1
ORDER
BY herotypeidcount DESC
, winrate DESC
) x
GROUP
BY playerid

Grand total of Columns using Sum (if) in mysql

I am trying to calculate the grand total of columns I just created with a SUM (if). I have a table with several product numbers but I want to get totals for specific products only. This is my query:
Select date(orders.OrderDate) As Date,
Sum(If((orders.ProductNumber = '1'), orders.Qty, 0)) As `Product 1`,
Sum(If((orders.ProductNumber = '2'), orders.Qty, 0)) As `Product 2`,
Sum(If((orders.ProductNumber = '3'), orders.Qty, 0)) As `Product 3`,
From orders
Group By date(orders.OrderDate)
I get the totals for each product in columns as expected, but when I try to get the grand total (Product 1 + product 2 + Product 3) using Sum(orders.Qty) as Total, I get the SUM of ALL products in the table and not only the 3 I am looking for.
How can I get the SUM(Product 1 + Product 2 + Product 3)?
Thank you
Try this:
SELECT DATE(o.OrderDate) AS date,
SUM(IF(o.ProductNumber = '1', o.Qty, 0)) AS `Product 1`,
SUM(IF(o.ProductNumber = '2', o.Qty, 0)) AS `Product 2`,
SUM(IF(o.ProductNumber = '3', o.Qty, 0)) AS `Product 3`,
SUM(IF(o.ProductNumber IN ('1', '2', '3'), o.Qty, 0)) AS `Total`
FROM orders o
GROUP BY DATE(o.OrderDate)
Simply pre-cutting rows other than 1, 2, 3. This is faster when ProductNumber is INDEXed column.
SELECT DATE(orders.OrderDate) AS Date,
SUM(IF((orders.ProductNumber = '1'), orders.Qty, 0)) AS `Product 1`,
SUM(IF((orders.ProductNumber = '2'), orders.Qty, 0)) AS `Product 2`,
SUM(IF((orders.ProductNumber = '3'), orders.Qty, 0)) AS `Product 3`,
SUM(orders.Qty) AS Total
FROM orders
WHERE
orders.ProductNumber IN ('1', '2', '3')
GROUP BY DATE(orders.OrderDate)

mysql use logic in where clause + invalid use of group function

I have the below mysql query that outputs the below image:
select
v.invoicenumber,
v.invoicedate,
v.haulier,
v.transporttype,
count(v.loadnumber) as totalloads,
sum(v.cost) as totalcost,
concat(SUM(if(invoiceapproved = 'yes', 1, 0)),' / ',count(v.loadnumber)) AS count, SUM(if(invoiceapproved = 'yes', 1, 0)) as approved
from v2loads v
where v.invoiced='yes'
group by invoicenumber
This query excutes 100%.
what I want to do is filter out any rows / data where the count is 100%. in the example output I want to filter out invoice 16 as it is 2/2 and 100%. so where
count(v.loadnumber) <> SUM(if(invoiceapproved = 'yes', 1, 0))
if I add this logic into the where clause it fails with error invalid use of group function. so below code does not work:
select v.invoicenumber,
v.invoicedate,
v.haulier,
v.transporttype,
count(v.loadnumber) as totalloads,
sum(v.cost) as totalcost,
concat(SUM(if(invoiceapproved = 'yes', 1, 0)),' / ',count(v.loadnumber)) AS count,
SUM(if(invoiceapproved = 'yes', 1, 0)) as approved
from v2loads v
where v.invoiced='yes' and
(count(v.loadnumber))<>(SUM(if(invoiceapproved = 'yes', 1, 0)))
group by invoicenumber
I got the following error:
error is #1111 - Invalid use of group function.
Any advice appreciated as always.
You can do this:
SELECT
*,
CONCAT(approved, ' / ', totalloads) AS count,
FROM
(
SELECT
v.invoicenumber,
v.invoicedate,
v.haulier,
v.transporttype,
COUNT(v.loadnumber) AS totalloads,
SUM(v.cost) AS totalcost,
SUM(if(invoiceapproved = 'yes', 1, 0)) As approved
FROM v2loads v
WHERE v.invoiced='yes'
GROUP BY invoicenumber
) t
WHERE totalloads <> approved;
select v.invoicenumber,
v.invoicedate,
v.haulier,
v.transporttype,
count(v.loadnumber) as totalloads,
sum(v.cost) as totalcost,
concat(SUM(if(invoiceapproved = 'yes', 1, 0)),' / ',count(v.loadnumber)) AS count,
SUM(if(invoiceapproved = 'yes', 1, 0)) as approved
from v2loads v
where v.invoiced='yes'
group by invoicenumber
having (count(v.loadnumber))<>(SUM(if(invoiceapproved = 'yes', 1, 0)))