mysql count occurrence of a string - mysql

I need to count how many times a couple categories appear in a column. They're storred as strings like Sports, Medicine, the column name is ct.category_name.
This is the query i'm adapting. I'd like a column for every category type.
select co.order_id, co.catalog_item_id, ct.category_name
from customer_order as co
join item_category as ic on (ic.item_id = co.customer_id )
join category_translations as ct on (ct.category_id = ic.category_id)
where co.paid = 1 and co.customer_id = 22500 and ct.locale = "en"
When I put this in the select statement it counts everything, I can see why, but I'm not sure which direction to go.
count(CASE
WHEN ct.category_name = "sports" THEN ct.category_name
ELSE 0
end) AS 'sports'
Again, i'd like the count for each string to be its own column. Any help would be much appreciated.
When I try:
select co.order_id, co.catalog_item_id, ct.category_name
, SUM(ct.category_name = "sports") AS `sports`
, SUM(ct.category_name = "medici") AS `medicine`
from customer_order as co
join item_category as ic on (ic.item_id = co.customer_id )
join category_translations as ct on (ct.category_id = ic.category_id)
where co.paid = 1 and co.customer_id = 22500 and ct.locale = "en"
It counts sports twice. Wrong place for the when? Results:
`23115 271708 sports 483 483`

It counts everything because COUNT increments its value for every not null value, and 0 is not NULL.
Possible solutions:
Replace 0 with NULL OR
Use SUM instead of COUNT:
SUM(CASE
WHEN ct.category_name = "sports" THEN 1
ELSE 0
end) AS 'sports'
or even
SUM(ct.category_name = "sports") AS `sports`

Related

MySQL JOIN with count / distinct

I've got multiple tables in my database.
Below is my SQL. It all works well for the majority.
How my system works is I may have a game which may sit in multiple competitions therefore will get called into this query more than once through the various JOINS.
It's like Liverpool playing a game but that game earns points for two competitions. It's not two games even though it'll appear twice. It's also not two rows in my database table 'game'.
What I have works for everything but the games that are in two competitions and where I want to do a few counts.
So my query code at the bottom works, but if I try add in
SUM(CASE WHEN g.isRanfurly = 1 THEN 1 ELSE 0 END) as TTLTests,
then this fails as it counts those games twice.
Any ideas?
SELECT DISTINCT(g.gameId), gd.playerId, t.teamName,
COUNT(distinct gd.gameId) as Appearances,
SUM(gd.tries) as TTLTries,
COUNT(CASE WHEN g.isTestMatch = 1 THEN 1 ELSE 0 END) as TTLTests,
IF(gd.homeaway = 1, g.team1Id, g.team2Id) as myteamId
FROM `gamedata` gd
JOIN `games` g ON gd.gameId = g.gameId
JOIN `teams` t ON t.teamId = IF(gd.homeaway = 1, g.team1Id, g.team2Id)
JOIN `roundgames` rg ON rg.gameId = gd.gameId
JOIN `rounds` r ON r.roundId = rg.roundId
JOIN `competitions` c ON r.competitionId = c.competitionId
WHERE `playerId` = 1 AND `didntPlay` = 0 AND t.teamType = 2
group by t.teamName
You can try the below - remove the else 0 from the conditional count
SELECT gd.playerId, t.teamName,
COUNT(distinct gd.gameId) as Appearances,
SUM(gd.tries) as TTLTries,
COUNT(CASE WHEN g.isTestMatch = 1 THEN 1 END) as TTLTests,
IF(gd.homeaway = 1, g.team1Id, g.team2Id) as myteamId
FROM `gamedata` gd
JOIN `games` g ON gd.gameId = g.gameId
JOIN `teams` t ON t.teamId = IF(gd.homeaway = 1, g.team1Id, g.team2Id)
JOIN `roundgames` rg ON rg.gameId = gd.gameId
JOIN `rounds` r ON r.roundId = rg.roundId
JOIN `competitions` c ON r.competitionId = c.competitionId
WHERE `playerId` = 1 AND `didntPlay` = 0 AND t.teamType = 2
group by gd.playerId, t.teamName
The solution was to use DISTINCT within the SUM
SUM(CASE WHEN g.isTestMatch = 1 THEN gd.tries ELSE 0 END) as TTLTestTries,

shows mysql records twice because of inner joining

In below query (Mentors) are 13 which shows me 26, while (SchoolSupervisor) are 5 which shows me 10 which is wrong. it is because of the Evidence which having 2 evidance, because of 2 evidence the Mentors & SchoolSupervisor values shows me double.
please help me out.
Query:
select t.c_id,t.province,t.district,t.cohort,t.duration,t.venue,t.v_date,t.review_level, t.activity,
SUM(CASE WHEN pr.p_association = "Mentor" THEN 1 ELSE 0 END) as Mentor,
SUM(CASE WHEN pr.p_association = "School Supervisor" THEN 1 ELSE 0 END) as SchoolSupervisor,
(CASE WHEN count(file_id) > 0 THEN "Yes" ELSE "No" END) as evidence
FROM review_m t , review_attndnce ra
LEFT JOIN participant_registration AS pr ON pr.p_id = ra.p_id
LEFT JOIN review_files AS rf ON rf.training_id = ra.c_id
WHERE 1=1 AND t.c_id = ra.c_id
group by t.c_id, ra.c_id order by t.c_id desc
enter image description here
You may perform the aggregations in a separate subquery, and then join to it:
SELECT
t.c_id,
t.province,
t.district,
t.cohort,
t.duration,
t.venue,
t.v_date,
t.review_level,
t.activity,
pr.Mentor,
pr.SchoolSupervisor,
rf.evidence
FROM review_m t
INNER JOIN review_attndnce ra
ON t.c_id = ra.c_id
LEFT JOIN
(
SELECT
p_id,
COUNT(CASE WHEN p_association = 'Mentor' THEN 1 END) AS Mentor,
COUNT(CASE WHEN p_association = 'School Supervisor' THEN 1 END) AS SchoolSupervisor,
FROM participant_registration
GROUP BY p_id
) pr
ON pr.p_id = ra.p_id
LEFT JOIN
(
SELECT
training_id,
CASE WHEN COUNT(file_id) > 0 THEN 'Yes' ELSE 'No' END AS evidence
FROM review_files
GROUP BY training_id
) rf
ON rf.training_id = ra.c_id
ORDER BY
t.c_id DESC;
Note that this also fixes another problem your query had, which was that you were selecting many columns which did not appear in the GROUP BY clause. Under this refactor, there is nothing wrong with your current select, because the aggregation take place in a separate subquery.
try adding this to the WHERE part of your query
AND pr.p_id IS NOT NULL AND rf.training_id IS NOT NULL
You can add a group by pr.p_id to remove the duplicate records there. Since, the group by on pr is not present as of now, there might be multiple records of same p_id for same ra
group by t.c_id, ra.c_id, pr.p_id order by t.c_id desc

how to select count of specific value while joining two tables

here i am joining two tables and this code fails to get the count of c.status
when c.status='Absent'
SELECT d.empReferenceID,
Count(c.status)
FROM emp_tbl d
LEFT JOIN empattendance c
on d.empReferenceID = c.RefrenceID
and c.status='PRESENT'
and month(c.CreatedOn)=5
and year(c.CreatedOn)=2017
where c.RefrenceID not in ('2075671')
GROUP BY d.empReferenceID;
Don't put conditions on an outer-joined table in the WHERE clause. Your where c.RefrenceID not in ('2075671') dismisses all outer-joined records and turns the join into an inner join.
Maybe you are looking for conditional aggregation, where you count different statuses and show the counts in the same result row:
SELECT d.empReferenceID,
Count(c.status) AS count_all,
Sum(c.status = 'PRESENT') AS count_present,
Sum(c.status = 'Absent') AS count_absent
FROM emp_tbl d
LEFT JOIN empattendance c
ON d.empReferenceID = c.RefrenceID
AND month(c.CreatedOn)=5
AND year(c.CreatedOn)=2017
WHERE d.empReferenceID not in ('2075671')
GROUP BY d.empReferenceID;
The SUM lines make use of MySQL's true = 1/ false = 0 by the way. You'd achieve the same with standard SQL: Sum(CASE WHEN c.status = 'PRESENT' THEN 1 ELSE 0 END) or Count(CASE WHEN c.status = 'PRESENT' THEN 1 END).

How to count the results of a where clause in order to calculate a proportion a MYSQL select clause?

I'm starting out with this query, which gives me back 8 records with a "claimed" status. I'm looking to see if any of the addresses in the invites-from-address column are different from that in the moves-from-address column :
SELECT i.id, i.company_id, i.status,
ia_f.base_street as "invites-from-address", a_f.base_street as "moves-from-address",
ia_t.base_street as "invites-to-address", a_t.base_street as "moves-to-address", i.`mover_first_name`,
i.mover_last_name, i.`to_address_id`
FROM invites i
JOIN moves m ON i.id = m.`claimed_invite_id`
JOIN `invite_addresses` ia_f ON ia_f.id = i.`from_address_id`
JOIN addresses a_f ON a_f.id = m.from_address_id
JOIN `invite_addresses` ia_t ON ia_t.id = i.to_address_id
JOIN addresses a_t ON a_t.id = m.to_address_id
WHERE i.`company_id` = 1040345
GROUP BY id
What I'm trying to do in this query below is to create an average_discrepancy column on the fly that shows the proportion of addresses that differ between invites-from-address and moves-from-address. I was able to successfully check for address discrepancies by using a WHERE clause that checks that ia_f.base_street is not equal to a_f.base_street (which are aliased to the columns invites-from-address and moves-from-address respectively) but when I put this WHERE clause inside the count function in my SELECT cause it doesn't work. Is it because I can't place a WHERE clause inside a SELECT or a count function or both? And is there also a problem with trying to divide the results of two calls to the count function in my SELECT clause ?
SELECT i.id, i.company_id, i.status,
count(WHERE ia_f.base_street != a_f.base_street)/count(i.status="claimed") as "average_discrepancy",
ia_f.base_street as "invites-from-address", a_f.base_street as "moves-from-address",
ia_t.base_street as "invites-to-address", a_t.base_street as "moves-to-address",
i.`mover_first_name`,
i.mover_last_name, i.`to_address_id`
FROM invites i
JOIN moves m ON i.id = m.`claimed_invite_id`
JOIN `invite_addresses` ia_f ON ia_f.id = i.`from_address_id`
JOIN addresses a_f ON a_f.id = m.from_address_id
JOIN `invite_addresses` ia_t ON ia_t.id = i.to_address_id
JOIN addresses a_t ON a_t.id = m.to_address_id
WHERE i.`company_id` = 1040345
AND i.status = "claimed"
You need to put this into a SUM instead of a COUNT. Something like this would do the trick:
SELECT i.id, i.company_id, i.status,
SUM(CASE WHEN ia_f.base_street != a_f.base_street THEN 1 ELSE 0 END)/ SUM(CASE WHEN i.status='claimed' THEN 1 ELSE 0 END) as 'average_discrepancy',
ia_f.base_street as 'invites-from-address',
a_f.base_street as 'moves-from-address',
ia_t.base_street as 'invites-to-address',
a_t.base_street as 'moves-to-address',
i.mover_first_name,
i.mover_last_name,
i.to_address_id
FROM invites i
JOIN moves m ON i.id = m.claimed_invite_id
JOIN invite_addresses ia_f ON ia_f.id = i.from_address_id
JOIN addresses a_f ON a_f.id = m.from_address_id
JOIN invite_addresses ia_t ON ia_t.id = i.to_address_id
JOIN addresses a_t ON a_t.id = m.to_address_id
WHERE i.company_id = 1040345
AND i.status = 'claimed'

Unable to get left outer join result in mysql query

SELECT
BB.NAME BranchName,
VI.NAME Village,
COUNT(BAC.CBSACCOUNTNUMBER) 'No.Of Accounts',
SUM(BAC.CURRENTBALANCE) SumOfAmount,
SUM(CASE
WHEN transactiontype = 'C' THEN amount
ELSE 0
END) AS CreditTotal,
SUM(CASE
WHEN transactiontype = 'D' THEN amount
ELSE 0
END) AS DebitTotal,
SUM(CASE
WHEN transactiontype = 'C' THEN amount
WHEN transactiontype = 'D' THEN - 1 * amount
ELSE 0
END) AS CurrentBalance
FROM
CUSTOMER CU,
APPLICANT AP,
ADDRESS AD,
VILLAGE VI,
BANKBRANCH BB,
BANKACCOUNT BAC
LEFT OUTER JOIN
accounttransaction ACT ON BAC.CBSACCOUNTNUMBER = ACT.BANKACCOUNT_CBSACCOUNTNUMBER
AND ACT.TRANDATE <= '2013-03-21'
AND BAC.ACCOUNTOPENINGDATE < '2013-03-21'
AND ACT.BANKACCOUNT_CBSACCOUNTNUMBER IS NOT NULL
WHERE
CU.CODE = AP.CUSTOMER_CODE
AND BAC.ENTITY = 'CUSTOMER'
AND BAC.ENTITYCODE = CU.CODE
AND AD.ENTITY = 'APPLICANT'
AND AD.ENTITYCODE = AP.CODE
AND AD.VILLAGE_CODE = VI.CODE
AND AD.STATE_CODE = VI.STATE_CODE
AND AD.DISTRICT_CODE = VI.DISTRICT_CODE
AND AD.BLOCK_CODE = VI.BLOCK_CODE
AND AD.PANCHAYAT_CODE = VI.PANCHAYAT_CODE
AND CU.BANKBRANCH_CODE = BB.CODE
AND BAC.CBSACCOUNTNUMBER IS NOT NULL
AND ACT.TRANSACTIONTYPE IS NOT NULL
GROUP BY BB.NAME , VI.NAME;
Here is my information
I have two tables bankaccount and accountransactions table
If account is created it will go to bankaccount table and if any transaction is done so respective account number record in accounttrasactiosns table however I want to display the count of total account numbers respective to the branch which the account number existed in bankaccount and it is may or may not available in accounttransactions table.
I'm guessing that the problem you have is that you are not getting results for accounts that do not have data in your accounttransaction table, even though you are using a LEFT JOIN. If that is true, the reason is because your join condition includes AND ACT.BANKACCOUNT_CBSACCOUNTNUMBER IS NOT NULL, which defeats the LEFT JOIN. You also have two conditions in your WHERE clause that I bet should not be there.
You should learn to use explicit join syntax in your coding. Your code will be much clearer if you do that; it separates the join conditions from the WHERE clause, which does a very different thing. I took a stab at re-writing your query as an illustration:
SELECT
BB.NAME BranchName,
VI.NAME Village,
COUNT(BAC.CBSACCOUNTNUMBER) 'No.Of Accounts',
SUM(BAC.CURRENTBALANCE) SumOfAmount,
SUM(ACT.CurrentBalance) CurrentBalance,
SUM(ACT.DebitTotal) DebitTotal,
SUM(ACT.CreditTotal) CreditTotal
FROM CUSTOMER CU
JOIN APPLICANT AP
ON AP.CUSTOMER_CODE = CU.CODE
JOIN ADDRESS AD
ON AD.ENTITYCODE = AP.CODE
JOIN VILLAGE VI
ON VI.CODE = AD.VILLAGE_CODE
AND VI.STATE_CODE = AD.STATE_CODE
AND VI.DISTRICT_CODE = AD.DISTRICT_CODE
AND VI.BLOCK_CODE = AD.BLOCK_CODE
AND VI.PANCHAYAT_CODE = AD.PANCHAYAT_CODE
JOIN BANKBRANCH BB
ON BB.CODE = CU.BANKBRANCH_CODE
JOIN BANKACCOUNT BAC
ON BAC.ENTITYCODE = CU.CODE
LEFT OUTER JOIN (
SELECT BANKACCOUNT_CBSACCOUNTNUMBER,
SUM(CASE
WHEN transactiontype = 'C' THEN amount
ELSE 0
END) AS CreditTotal,
SUM(CASE
WHEN transactiontype = 'D' THEN amount
ELSE 0
END) AS DebitTotal,
SUM(CASE
WHEN transactiontype = 'C' THEN amount
WHEN transactiontype = 'D' THEN - 1 * amount
ELSE 0
END) AS CurrentBalance
FROM accounttransaction
WHERE TRANDATE <= '2013-03-21'
GROUP BY BANKACCOUNT_CBSACCOUNTNUMBER
) ACT
ON ACT.BANKACCOUNT_CBSACCOUNTNUMBER = BAC.CBSACCOUNTNUMBER
AND BAC.ACCOUNTOPENINGDATE < '2013-03-21'
WHERE BAC.ENTITY = 'CUSTOMER'
AND AD.ENTITY = 'APPLICANT'
GROUP BY BB.NAME , VI.NAME;
I removed this line from the LEFT JOIN condition
AND ACT.BANKACCOUNT_CBSACCOUNTNUMBER IS NOT NULL
And I removed these two lines from the WHERE clause
AND BAC.CBSACCOUNTNUMBER IS NOT NULL
AND ACT.TRANSACTIONTYPE IS NOT NULL
If that does not solve your problem, please revise your question to explain further.
UPDATE: Based on comments, the query is revised to calculate the debit, credit, and current balance by account using a derived table.
Also note the placement of the BAC.ACCOUNTOPENINGDATE < '2013-03-21' condition on left join. As written, this will return all accounts regardless of the opening date. If you want to only show accounts that were opened before that date, this condition should be moved to the WHERE clause.