How to use Group By correclty? - mysql

I have this query that worked fine:
select isnull(email,'') as Email ,isnull([ERPM First Name],'')+' '+isnull([ERPM Last Name],'')[User Name],
geo,CustomerID,BusinessID,courseid, MIN (CompletionDate) [1st Training Course],
CASE WHEN COURSEID IN (37445,37644,37443,37778,37435,37733,37584,37483,37392,37817,
37259,37597,37391,37393,37792,37816,37256,37257,37258,37484,37485,37486)
THEN 'Yes' ELSE 'No'
END AS [Is it a campaing course?],
CASE WHEN CompletionDate BETWEEN '2017-03-10' AND '2017-09-03' THEN 'Yes' ELSE 'No'
END AS [During Campaign],
CASE WHEN COURSEID IN (37256,37257,37258,37484,37485,37486) AND
CompletionDate BETWEEN '2017-03-10' AND '2017-09-03' THEN 'ON Period Bonus' ELSE '-'
END AS [1st BONUS]
from vw_Training_Cube
where [Is disti or subdisti?] = 'No' and [Is test account?] = 'No'
and Email<>'0'
GROUP BY isnull(email,''),isnull([ERPM First Name],'')+' '+isnull([ERPM Last Name],''),geo,CustomerID,BusinessID,courseid,
CASE WHEN COURSEID IN (37445,37644,37443,37778,37435,37733,37584,37483,37392,
37817,37259,37597,37391,37393,37792,37816,37256,37257,37258,37484,37485,37486)
THEN 'Yes' ELSE 'No'
END,
CASE WHEN CompletionDate BETWEEN '2017-03-10' AND '2017-09-03' THEN 'Yes' ELSE 'No'
END,
CASE WHEN COURSEID IN (37256,37257,37258,37484,37485,37486) AND
CompletionDate BETWEEN '2017-03-10' AND '2017-09-03' THEN 'ON Period Bonus' ELSE '-5'
END
but now instead of grouping by email, I want to group by business id. But simply swapping the order doesnt solve the problem.

Unless you need an aggregate function such as COUNT() MIN() or MAX() then you can simplify your query by using select distinct.
SELECT DISTINCT
ISNULL(email, '')
AS Email
, ISNULL([ERPM First Name], '') + ' ' + ISNULL([ERPM Last Name], '')
[User Name]
, geo
, CustomerID
, BusinessID
, courseid
, MIN(CompletionDate) [1st Training Course]
, CASE
WHEN COURSEID IN (37445, 37644, 37443, 37778, 37435, 37733, 37584, 37483, 37392, 37817,
37259, 37597, 37391, 37393, 37792, 37816, 37256, 37257, 37258, 37484, 37485, 37486) THEN
'Yes'
ELSE
'No'
END AS [Is it a campaing course?]
, CASE
WHEN CompletionDate BETWEEN '2017-03-10' AND '2017-09-03' THEN
'Yes'
ELSE
'No'
END AS [During Campaign]
, CASE
WHEN COURSEID IN (37256, 37257, 37258, 37484, 37485, 37486) AND
CompletionDate BETWEEN '2017-03-10' AND '2017-09-03' THEN
'ON Period Bonus'
ELSE
'-'
END AS [1st BONUS]
FROM vw_Training_Cube
WHERE [Is disti or subdisti?] = 'No'
AND [Is test account?] = 'No'
AND Email <> '0'
ORDER BY BusinessID
To reduce the rows further, you also need to remove columns - OR - start using aggregate functions. e.g. the following would produce the minimum set of rows to list every BusinessID that meets the where conditions.
SELECT DISTINCT
BusinessID
FROM vw_Training_Cube
WHERE [Is disti or subdisti?] = 'No'
AND [Is test account?] = 'No'
AND Email <> '0'
ORDER BY BusinessID
;
Keep adding columns to that to see the effect on number of rows.

Related

.PolTypeLOB' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause. Have tried to debug

I have tried to debug this for hours. Any help or tips will be appreciated
SELECT PA.PolExec, SUM(ISNULL(PR.Revenue,0) + ISNULL(PF.Revenue,0)) AS Revenue,
CASE P.PolTypeLOB
WHEN 'Me%' THEN 'MED'
WHEN 'Pres' THEN 'MED'
ELSE CASE P.TypeOfBus
WHEN 1 THEN 'PL'
WHEN 2 THEN 'CL'
ELSE 'BEN'
END
END AS PolType
GROUP BY PA.PolExec
ORDER BY PA.PolExec
Use MAX if PolTypeLOB is always the same for all PolExec
SELECT PA.PolExec, SUM(ISNULL(PR.Revenue,0) + ISNULL(PF.Revenue,0)) AS Revenue,
MAX(CASE P.PolTypeLOB
WHEN 'Me%' THEN 'MED'
WHEN 'Pres' THEN 'MED'
ELSE CASE P.TypeOfBus
WHEN 1 THEN 'PL'
WHEN 2 THEN 'CL'
ELSE 'BEN'
END
END) AS PolType
GROUP BY PA.PolExec
ORDER BY PA.PolExec
as the error me3ssage says , all columns in a SELECT have3 to be in the GROUP BY or have a aggregation function

SQL IF statement with a print

What am I doing wrong? It needs to display yes if more people are single than married and no if viceversa. I just want it to display yes or no only.
IF
select COUNT(StudMaritalStatus) from students WHERE StudMaritalStatus = "M"
<
select COUNT(StudMaritalStatus) from students WHERE StudMaritalStatus = "S"
Print 'Yes'
ELSE
Print 'No';
You want something like this:
select case when married >= single then 'M' else 'S' end
from
(
select sum(case when StudMaritalStatus = 'M' then 1 else 0 end) married
, sum (case when StudMaritalStatus = 'S' then 1 else 0 end) single
from students
) derivedTable
Tie breaking depends on your business requirements, which none of us know.
well considering that MySQL uses:
IF expression THEN
expression
ELSE
ENDIF;
you would be better of not doing it with a select statement
DECLARE married int, single int
SET married = select COUNT(StudMaritalStatus) from students WHERE StudMaritalStatus = 'M'
SET single = select COUNT(StudMaritalStatus) from students WHERE StudMaritalStatus = 'S'
IF married < single THEN
PRINT 'YES'
ELSE
PRINT 'NO'
END IF
In answer yes your syntax was wrong
https://dev.mysql.com/doc/refman/5.7/en/if.html

MySQL CASE , SUM, GROUP BY

I want sum of payment status from two differnt columns based on paymentstatus value - but this query returns null for sum. Why is it not working?
select payment_status,
CASE
WHEN 'PAID' THEN sum(paid_amount)
when 'Not Paid' then sum(total_amount_due )
END
from monthly_fee
group by payment_status;
select sum(CASE WHEN payment_status = 'PAID' THEN paid_amount else 0 end) as paid,
sum(CASE WHEN payment_status = 'Not Paid' THEN total_amount_due else 0 end) as due
from monthly_fee
If you want this conditionally, you need to include the column in the case:
select payment_status,
(case payment_status
when 'Paid' then sum(paid_amount)
when 'Not Paid' then sum(total_amount_due )
end)
from monthly_fee
group by payment_status;
This seems like a strange way to write the query, unless you really want two rows.
Your WHEN clauses aren't a condition.
I'd expect to see something like
select payment_status,
CASE
WHEN payment_status = 'PAID' THEN sum(paid_amount)
when payment_status = 'Not Paid' then sum(total_amount_due )
END
from monthly_fee
group by payment_status;
You can try the following query:
select sum(if(payment_status = 'PAID', paid_amount, 0)
+ if(payment_status = 'Not Paid', total_amount_due, 0))
from monthly_fee
group by payment_status;

MYSQL - Showing status input as it's own column

I'm having trouble writing a SQL query to show the status of a row as it's own column as shown in the picture.
I was thinking of using an alias for Status as:
SELECT 'Table A.Date', 'Table A.Status' as ... FROM Table A;
But this doesn't resolve the issue on how to display each status type as their own column and number value.
Can someone point out how to do this?
Try this one. I used CASE statement to conditionally count the status as one depending on the status type given.
SELECT
Date,
SUM(CASE WHEN Status='Pending' THEN 1 ELSE 0 END)Pending,
SUM(CASE WHEN Status='Completed' THEN 1 ELSE 0 END)Completed,
SUM(CASE WHEN Status='Cancelled' THEN 1 ELSE 0 END)Cancelled
FROM Table A
WHERE Date='2014-01-01'
GROUP BY Date
Try this:
select A.date,
count(
case
when A.Status='Pending'
Then 1
Else NULL
End
) as Pending,
count(
case
when A.Status='Completed'
Then 1
Else NULL
End
) as Completed,
count(
case
when A.Status='Cancelled'
Then 1
Else NULL
End
) as Cancelled
From A
group by A.date

get count of two table fields in one query

I am trying to get the count of females and males in the gender field of a table.
Is there a way to get the count of each in one query?
Something like:
select * from table count(where gender = 'm') as total_males, count(where gender = 'f') as total_females;
or will it require two queries?
select count(*) from table where gender = 'm';
select count(*) from table where gender = 'f';
This is basically a PIVOT. MySQL does not have a pivot so you can use an aggregate function with a CASE statement to perform this:
select
sum(case when gender = 'm' then 1 else 0 end) Total_Male,
sum(case when gender = 'f' then 1 else 0 end) Total_Female
from yourtable
See SQL Fiddle with Demo
Or using COUNT:
select
count(case when gender = 'm' then 1 else null end) Total_Male,
count(case when gender = 'f' then 1 else null end) Total_Female
from yourtable;
See SQL Fiddle with Demo
Something like this will work:
SELECT SUM(IF(t.gender='m',1,0)) AS total_males
, SUM(IF(t.gender='f',1,0)) AS total_females
FROM mytable t
The "trick" here is that we are using a conditional test to return either a 0 or a 1 for each row, and then adding up the 0's and 1's. To make this a little more clear, I am using the SUM aggregate function rather than COUNT, although COUNT could be used just as easily, though we'd need to return a NULL in place of the zero.
SELECT COUNT(IF(t.gender='m',1,NULL)) AS total_males
, COUNT(IF(t.gender='f',1,NULL)) AS total_females
FROM mytable t
Consider that the two expressions in the SELECT list of this query:
SELECT COUNT(1)
, SUM(1)
FROM mytable t
Will return the same value.
If you want to avoid the MySQL IF function, this can also be done using the ANSI SQL CASE expression:
SELECT SUM( CASE WHEN t.gender = 'm' THEN 1 ELSE 0 END )) AS total_males
, SUM( CASE WHEN t.gender = 'f' THEN 1 ELSE 0 END )) AS total_females
FROM mytable t
select sum(case when gender='m' then 1 else null end) as total_males, sum(case when gender='f' then 1 else null end) as total_females from ...
Should work just fine!
If your only issue is to avoid two queries, you can always write two queries as subselects of one query.
Select (select 1 from dual) as one, (select 2 from dual) as two from dual
This would work for your scenario, too.