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

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)))

Related

SQL query to break down day by day for entire week

I have a table of sales in MySQL. I'm trying in 1 query to get a view that looks like this:
AGENT, MONDAY_TOTAL, TUESDAY_TOTAL,WEDNESDAY_TOTAL,THURSDAY_TOTAL,FRIDAY_TOTAL,SATURDAY_TOTAL
What I have so far is this:
SELECT DISTINCT(repname), DAYOFWEEK(sub_date), COUNT(*)
FROM `NewDeals`
WHERE WEEK(sub_date) = WEEK(CURRENT_DATE)
GROUP BY repname, DAYOFWEEK(sub_date)
That gives me values that look like this:
AGENT, DAYOFWEEK, TOTAL
Naturally, I can turn the output of the second example into the first in my code, but if I can just do it with the SQL query I'd rather do that.
SELECT repname,
SUM(IF(DAYOFWEEK(sub_date)=2, 1, 0)) AS MONDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=3, 1, 0)) AS TUESDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=4, 1, 0)) AS WEDNESDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=5, 1, 0)) AS THURSDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=6, 1, 0)) AS FRIDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=7, 1, 0)) AS SATURDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=1, 1, 0)) AS SUNDAY_TOTAL
FROM `NewDeals`
WHERE WEEK(sub_date) = WEEK(CURRENT_DATE)
GROUP BY repname
But getting results for days that haven't happened yet.
Update: This was because we did not constrain the year:
Solution:
SELECT repname,
SUM(IF(DAYOFWEEK(sub_date)=2, 1, 0)) AS MONDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=3, 1, 0)) AS TUESDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=4, 1, 0)) AS WEDNESDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=5, 1, 0)) AS THURSDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=6, 1, 0)) AS FRIDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=7, 1, 0)) AS SATURDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=1, 1, 0)) AS SUNDAY_TOTAL
FROM `NewDeals`
WHERE WEEK(sub_date) = WEEK(CURRENT_DATE) AND YEAR(sub_date) = YEAR(CURRENT_DATE)
GROUP BY repname
You can use an IF function to select only DAYOFWEEK-related counts, then sum every counted element inside the SUM aggregate function as follows:
SELECT repname,
SUM(IF(DAYOFWEEK(sub_date)=2, 1, 0)) AS MONDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=3, 1, 0)) AS TUESDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=4, 1, 0)) AS WEDNESDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=5, 1, 0)) AS THURSDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=6, 1, 0)) AS FRIDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=7, 1, 0)) AS SATURDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=1, 1, 0)) AS SUNDAY_TOTAL
FROM `NewDeals`
WHERE WEEK(sub_date) = WEEK(CURRENT_DATE)
GROUP BY repname
Note: when the DISTINCT keyword is applied, it will work on every selected field of your SELECT clause, you can't make a distinct of a single field using parentheses.

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.

How to SUM result both SUMs SQL?

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`

Subsequence in MySQL/CakePHP

In my mysql table I have a field which is a 4 letter Myers-Briggs personality type. I would like to search through the table and match when the personality type matches the one in the query by having 2 aspects in common. The way I understand this, it is really just finding the longest common subsequence of the two and testing that it is >= 2
Example:
'ISTJ' would match with 'INFJ', because the length of the common subsequence is 'IJ' >= 2
and
'ISTJ' would not match with 'INFP', because the length of the common subsequence is 'I' <= 2
Is there a way to do this in a mysql query? I am using CakePHP for the querying, so if you know how to do this with Cake that would also be helpful.
The Myer-Briggs personality types are positional. This means that you can compare character by character.
Here is one method, where you just have to put in the comparison string once:
select t.*
from (select t.*,
(case when substring(t.MyerBriggs, 1, 1) = substring(const.comp, 1, 1)
then 1 else 0
end) as MB1,
(case when substring(t.MyerBriggs, 2, 1) = substring(const.comp, 2, 1)
then 1 else 0
end) as MB2,
(case when substring(t.MyerBriggs, 3, 1) = substring(const.comp, 3, 1)
then 1 else 0
end) as MB3,
(case when substring(t.MyerBriggs, 4, 1) = substring(const.comp, 4, 1)
then 1 else 0
end) as MB4
from t cross join
(select 'INFJ' as comp) const
)
where (MB1+MB2+MB3+MB4) >= 2
You can actually simplify this in MySQL as:
select t.*
from t cross join
(select 'INFJ' as comp) const
where (if(substring(t.MyerBriggs, 1, 1) = substring(const.comp, 1, 1), 1, 0) +
if(substring(t.MyerBriggs, 2, 1) = substring(const.comp, 2, 1), 1, 0) +
if(substring(t.MyerBriggs, 3, 1) = substring(const.comp, 3, 1), 1, 0) +
if(substring(t.MyerBriggs, 4, 1) = substring(const.comp, 4, 1), 1, 0)
) >= 2
If I understand the Myers-Briggs thingy properly, there are two possibilities for each of the four categorisation axis, and the order of the letters is constant (and therefore carries no meaning).
In this case, you could use four two-state columns like the below, instead of one string:
CREATE TABLE profile (
user_id INT,
EI ENUM ('E', 'I'),
SN ENUM ('S', 'N'),
TF ENUM ('T', 'F'),
JP ENUM ('J', 'P')
);
Profile 'ISTJ' would be inserted like this:
INSERT INTO profile VALUE (1, 'I', 'S', 'T', 'J');
Matching with profile 'INFJ' would look like this:
SELECT * FROM profile WHERE
(EI = 'I') + (SN = 'N') + (TF = 'F') + (JP = 'J') >= 2

Multiple nested if statment in MySQL query

I'm trying the query below and MySQL gave me this error: Invalid use of group function
SELECT C.`some_name`,
SUM(IF(A.`med_type` = 1, SUM(A.`med_qty`), 0)) AS total,
SUM(IF(A.`is_rejected` = 4, 1 , 0)) AS approved,
SUM(IF(A.`is_rejected` = 2, 1 , 0)) AS qeue,
SUM(IF(A.`is_rejected` = 3, 1 , 0)) AS rejected,
SUM(IF(A.`is_rejected` = 1, 1 , 0)) AS fresh
FROM `ne_media` A
INNER JOIN `ne_member` B ON A.`mem_id` = B.`mem_id`
INNER JOIN `ne_some` C ON B.`some_id` = C.`some_id`
GROUP BY C.`some_id`;
I want to sum med_qty just if med_type = 1.
How do I do it?
Use:
SUM(CASE WHEN (A.`med_type` = 1) THEN A.`med_qty` ELSE 0 END)) AS total,
or:
SUM(IF(A.`med_type` = 1, A.`med_qty`, 0)) AS total,
You can't do aggregates on aggregates like you tried to in the original.