mysql count for same column but two counts - mysql

I am trying to do a count on the same column having different status, how can i do it, i tried but i am running into bunch of issues
SELECT
distinct tblsmsgroups.GroupName,
tblsmsphones.PhoneNumber,
tblsmsphones.GroupID,
count(case when status = 1 then) as active
FROM
tblsmscustomers,
tblsmsgroups
INNER JOIN tblsmsphones
ON tblsmsgroups.groupID = tblsmsphones.GroupID
status = 1 then active how many, and status = 0 , then counts of how many, i am still stuck at the syntactical difference as to how can i do, any idea?

Well, if you want to add stuff up, you want a group by.
If you want to join tables, you want join -- never use commas for that purpose.
That suggest something like:
SELECT g.GroupName, p.PhoneNumber, p.GroupID,
SUM(status = 1) as active,
SUM(status = 0) as not_active
FROM tblsmsgroups g JOIN
tblsmsphones p
ON g.groupID = p.GroupID JOIN
tblsmscustomers c
ON c.customerID = p.customerID -- have to guess the JOIN condition here
GROUP BY g.GroupName, p.PhoneNumber, p.GroupID;
Note: Your question does not have enough information to understand the join conditions between the three tables; the above is a reasonable guess.

You probably want something like this:
SELECT
tblsmsgroups.GroupName,
tblsmsphones.PhoneNumber,
tblsmsphones.GroupID,
sum(status = 1) as active_count,
sum(status != 1) as inactive_count
FROM
tblsmscustomers ,
tblsmsgroups
INNER JOIN tblsmsphones ON tblsmsgroups.groupID = tblsmsphones.GroupID
GROUP BY GroupName, PhoneNumber, GroupID

Related

MySQL Query to fetch Distinct Rows with latest status

I have 3 tables, namely - areas, works and jobs.
areas works jobs
----- ----- -----
area_id work_id area_id (FK)
area_name task work_id (FK)
area_type app_area status
updated_at
I'm trying to select the total list of areas cross joined with works such that I have all the permutations for areas vs works, then have the LATEST status of that combination, if it exists. I want distinct rows for each area_id-work_id combination.
I put together the below query statement but some rows have statuses displayed as NULL when they actually exist. My guess is there's something wrong with my inner SELECT statement but try as I may, I could not get it to work, any idea what's wrong with my statement?
SELECT area_name, works.task, jobs.status
FROM areas
CROSS JOIN works ON works.work_id = works.work_id
LEFT JOIN jobs ON jobs.status = (SELECT jobs.status FROM jobs ORDER BY jobs.updated_at DESC LIMIT 1) AND
(jobs.work_id = works.work_id AND jobs.area_id = areas.area_id)
WHERE works.app_area = 'zone' AND areas.area_type = 'zone'
ORDER BY areas.area_id, works.work_id, jobs.updated_at;
Your logic for the last status should be using the date not the status. The logic looks like this:
SELECT a.area_name, w.task, j.status
FROM areas a CROSS JOIN
works w LEFT JOIN
jobs j
ON j.work_id = w.work_id AND j.area_id = a.area_id AND
j.updated_at = (SELECT MAX(j2.updated_at)
FROM jobs j2
WHERE j2.work_id = w.work_id AND j2.area_id = a.area_id
)
WHERE w.app_area = 'zone' AND a.area_type = 'zone'
ORDER BY a.area_id, w.work_id, j.updated_at;
This also fixes some other problems, such as having an ON clause with CROSS JOIN.
If you want to solve it by your own query then please replace this line in the left join sub query
SELECT j.status FROM jobs j ORDER BY jobs.updated_at DESC LIMIT 1
Using Gordon Solution, I think this is another way you can do it. you'll have to test to see which way works faster for you.
SELECT a.area_name, w.task, (SELECT MAX(j2.updated_at)
FROM jobs j2
WHERE j2.work_id = w.work_id AND j2.area_id = a.area_id
) status
FROM areas a CROSS JOIN
works w LEFT JOIN
jobs j
ON j.work_id = w.work_id AND j.area_id = a.area_id
WHERE w.app_area = 'zone' AND a.area_type = 'zone'
ORDER BY a.area_id, w.work_id, j.updated_at;

sql counts wrong number of likes

I have written an sql statement that besides all the other columns should return the number of comments and the number of likes of a certain post. It works perfectly when I don't try to get the number of times it has been shared too. When I try to get the number of time it was shared instead it returns a wrong number of like that seems to be either the number of shares and likes or something like that. Here is the code:
SELECT
[...],
count(CS.commentId) as shares,
count(CL.commentId) as numberOfLikes
FROM
(SELECT *
FROM accountSpecifics
WHERE institutionId= '{$keyword['id']}') `AS`
INNER JOIN
account A ON A.id = `AS`.accountId
INNER JOIN
comment C ON C.accountId = A.id
LEFT JOIN
commentLikes CL ON C.commentId = CL.commentId
LEFT JOIN
commentShares CS ON C.commentId = CS.commentId
GROUP BY
C.time
ORDER BY
year, month, hour, month
Could you also tell me if you think this is an efficient SQL statement or if you would do it differently? thank you!
Do this instead:
SELECT
[...],
(select count(*) from commentLikes CL where C.commentId = CL.commentId) as shares,
(select count(*) from commentShares CS where C.commentId = CS.commentId) as numberOfLikes
FROM
(SELECT *
FROM accountSpecifics
WHERE institutionId= '{$keyword['id']}') `AS`
INNER JOIN account A ON A.id = `AS`.accountId
INNER JOIN comment C ON C.accountId = A.id
GROUP BY C.time
ORDER BY year, month, hour, month
If you use JOINs, you're getting back one result set, and COUNT(any field) simply counts the rows and will always compute the same thing, and in this case the wrong thing. Subqueries are what you need here. Good luck!
EDIT: as posted below, count(distinct something) can also work, but it's making the database do more work than necessary for the answer you want to end up with.
Quick fix:
SELECT
[...],
count(DISTINCT CS.commentId) as shares,
count(DISTINCT CL.commentId) as numberOfLikes
Better approach:
SELECT [...]
, Coalesce(shares.numberOfShares, 0) As numberOfShares
, Coalesce(likes.numberOfLikes , 0) As numberOfLikes
FROM [...]
LEFT
JOIN (
SELECT commentId
, Count(*) As numberOfShares
FROM commentShares
GROUP
BY commentId
) As shares
ON shares.commentId = c.commentId
LEFT
JOIN (
SELECT commentId
, Count(*) As numberOfLikes
FROM commentLikes
GROUP
BY commentId
) As likes
ON likes.commentId = c.commentId

MAX() Function not working as expected

I've created sqlfiddle to try and get my head around this http://sqlfiddle.com/#!2/21e72/1
In the query, I have put a max() on the compiled_date column but the recommendation column is still coming through incorrect - I'm assuming that a select statement will need to be inserted on line 3 somehow?
I've tried the examples provided by the commenters below but I think I just need to understand this from a basic query to begin with.
As others have pointed out, the issue is that some of the select columns are neither aggregated nor used in the group by clause. Most DBMSs won't allow this at all, but MySQL is a little relaxed on some of the standards...
So, you need to first find the max(compiled_date) for each case, then find the recommendation that goes with it.
select r.case_number, r.compiled_date, r.recommendation
from reporting r
join (
SELECT case_number, max(compiled_date) as lastDate
from reporting
group by case_number
) s on r.case_number=s.case_number
and r.compiled_date=s.lastDate
Thank you for providing sqlFiddle. But only reporting data is given. we highly appreciate if you give us sample data of whole tables.
Anyway, Could you try this?
SELECT
`case`.number,
staff.staff_name AS ``case` owner`,
client.client_name,
`case`.address,
x.mx_date,
report.recommendation
FROM
`case` INNER JOIN (
SELECT case_number, MAX(compiled_date) as mx_date
FROM report
GROUP BY case_number
) x ON x.case_number = `case`.number
INNER JOIN report ON x.case_number = report.case_number AND report.compiled_date = x.mx_date
INNER JOIN client ON `case`.client_number = client.client_number
INNER JOIN staff ON `case`.staff_number = staff.staff_number
WHERE
`case`.active = 1
AND staff.staff_name = 'bob'
ORDER BY
`case`.number ASC;
Check below query:
SELECT c.number, s.staff_name AS `case owner`, cl.client_name,
c.address, MAX(r.compiled_date), r.recommendation
FROM case c
INNER JOIN (SELECT r.case_number, r.compiled_date, r.recommendation
FROM report r ORDER BY r.case_number, r.compiled_date DESC
) r ON r.case_number = c.number
INNER JOIN client cl ON c.client_number = cl.client_number
INNER JOIN staff s ON c.staff_number = s.staff_number
WHERE c.active = 1 AND s.staff_name = 'bob'
GROUP BY c.number
ORDER BY c.number ASC
SELECT
case.number,
staff.staff_name AS `case owner`,
client.client_name,
case.address,
(select MAX(compiled_date)from report where case_number=case.number),
report.recommendation
FROM
case
INNER JOIN report ON report.case_number = case.number
INNER JOIN client ON case.client_number = client.client_number
INNER JOIN staff ON case.staff_number = staff.staff_number
WHERE
case.active = 1 AND
staff.staff_name = 'bob'
GROUP BY
case.number
ORDER BY
case.number ASC
try this

Grouping issue with SELECT query

I am building a very basic level Event management & Invitation system. For that I have build 2 tables and using a query to list all events with their Invitation counts as
1. Total Invitations Sent
2. Total Accepted
3. Total Rejected
4. Total Waiting
Below is the query
SELECT
*,
count(im.event_id_fk) as total_invitations,
count(im2.event_id_fk) as total_accepted,
count(im3.event_id_fk) as total_rejected,
count(im4.event_id_fk) as total_waiting
FROM event_mst em
LEFT JOIN invitation_mst im
ON (em.event_id_pk = im.event_id_fk)
LEFT JOIN invitation_mst im2
ON (em.event_id_pk = im2.event_id_fk AND im2.status = 'Accept')
LEFT JOIN invitation_mst im3
ON (em.event_id_pk = im3.event_id_fk AND im3.status = 'Reject')
LEFT JOIN invitation_mst im4
ON (em.event_id_pk = im4.event_id_fk AND im4.status = 'Waiting')
GROUP BY
im.event_id_fk,
im2.event_id_fk,
im3.event_id_fk,
im4.event_id_fk
ORDER BY
em.date_added DESC
Now the issue is that this query is giving Wrong counts, e.g. if there are total 3 Invitations sent, it is giving 9. If there are 5 invitations sent, it is giving 25.
so it seems that it is multiplying with itself and returning the result. I know there must be something wrong with this select query. Anyone correct me this query ?
Thanks in advance.
This is the simpliest solution for mysql because it supports boolean calculation.
SELECT event_id_pk,
COUNT(*) as total_invitations,
SUM(status = 'Accept') as total_accepted,
SUM(status = 'Reject') as total_rejected,
SUM(status = 'Waiting') as total_waiting
FROM event_mst
GROUP BY event_id_pk
but the query will not give you full details on the invitation, in order to do that, you can wrap the query in the subquery and join that with the original table itself,
SELECT a.*,
b.total_invitations,
b.total_rejected,
b.total_waiting
FROM event_mst a
INNER JOIN
(
SELECT event_id_pk,
COUNT(*) as total_invitations,
SUM(status = 'Accept') as total_accepted,
SUM(status = 'Reject') as total_rejected,
SUM(status = 'Waiting') as total_waiting
FROM event_mst
GROUP BY event_id_pk
) b ON a.event_id_pk = b.event_id_pk

Sums are being multiplied in query

I am working on 2 problems for homework and after many hours I have just about solved them both, the last issue I have is that both of my queries are coming back with doubled numerical values instead of single.
Here is what I have:
SELECT SUM(P.AMT_PAID) AS TOTAL_PAID, C.CITATION_ID, C.DATE_ISSUED, SUM(V.FINE_CHARGED) AS TOTAL_CHARGED
FROM PAYMENT P, CITATION C, VIOLATION_CITATION V
WHERE V.CITATION_ID = C.CITATION_ID
AND C.CITATION_ID = P.CITATION_ID
GROUP BY C.CITATION_ID;
and my other one:
SELECT C.CITATION_ID, C.DATE_ISSUED, SUM(V.FINE_CHARGED) AS TOTAL_CHARGED, SUM(P.AMT_PAID) AS TOTAL_PAID, SUM(V.FINE_CHARGED) - SUM(P.AMT_PAID) AS TOTAL_OWED
FROM (CITATION C)
LEFT JOIN VIOLATION_CITATION V
ON V.CITATION_ID = C.CITATION_ID
LEFT JOIN PAYMENT P
ON P.CITATION_ID = C.CITATION_ID
GROUP BY C.CITATION_ID
ORDER BY TOTAL_OWED DESC;
I am sure there is just something that I am overlooking. If someone else could kindly tell me where I went awry it would be a great help.
Select Sum(P.Amt_Paid) As Total_Paid, C.Citation_Id
, C.Date_Issued, Sum(V.Fine_Charged) As Total_Charged
From Payment P
Join Citation C
On C.Citation_Id = P.Citation_Id
Join Violation_Citation V
On V.Citation_Id = C.Citation_Id
Group By C.Citation_Id
First, you should use the JOIN syntax instead of using the comma-delimited list of tables. It makes it easier to read, more standardized and will help prevent problems by overlooking a filtering clause.
Second, the most likely reason for having a sum that is too large is due to the join to the VIOLATION_CITATION table. If you remove the Group By and columns with aggregate functions, you will likely see that P.AMT_PAID is repeated for each instance of VIOLATION_CITATION. Perhaps, the following will solve the problem:
Select Coalesce(PaidByCitation.TotalAmtPaid,0) As Total_Paid
, C.Citation_Id, C.Date_Issued
, Coalesce(ViolationByCitation.TotalCharged,0) As Total_Charged
, Coalesce(ViolationByCitation.TotalCharged,0)
- Coalesce(PaidByCitation.TotalAmtPaid,0) As Total_Owed
From Citation As C
Left Join (
Select P.Citation_Id, Sum( P.Amt_Paid ) As TotalAmtPaid
From Payment As P
Group By P.Citation_Id
) As PaidByCitation
On PaidByCitation.Citation_Id = C.Citation_Id
Left Join (
Select V.Citation_Id, Sum( V.Find_Charged ) As TotalCharged
From Violation_Citation As V
Group By V.Citation_Id
) As ViolationByCitation
On ViolationByCitation.Citation_Id = C.Citation_Id
The use of Coalesce is to ensure that if the left join returns no rows for a given Citation_ID value, that we replace the Null with zero.