Count specific values in column - mysql

I'm trying to count the number of times multiple words appears in a column named sg_event but currently run each one separately. Does anyone know how I can combine this into one query.
select count(*) from metrics
WHERE sg_event = 'open';
select count(*) from metrics
WHERE sg_event = 'delivered';
select count(*) from metrics
WHERE sg_event = 'click';
My desired outcome is as follows,
open_count, delivered_count, click_count

You can use conditional sum for this
select
sum( case when sg_event = 'open' then 1 else 0 end ) as `open_count`,
sum( case when sg_event = 'delivered' then 1 else 0 end ) as `delivered_count`,
sum( case when sg_event = 'click' then 1 else 0 end ) as `click_count`
from metrics

You can use the standard sql feature group by:
SELECT count(*), sg_event
FROM metrics
WHERE sg_event IN ( 'open', 'delivered', 'click')
GROUP BY sg_event;
You should get something like
10 open
15 delivered
76 click
so each line get one sum.
Of course you can sort your results (e.g.: ORDER BY 1, to sort by count column)
This solution is more flexible, cause you can specify a lot more values to inspect (here for sg_event), maybe a join with a table which hold all your interested sg_events.

As shown in the answer by Abhik Chakraborty you can use the caseexpression to conditionally aggregate data, but since MySQL evaluates boolean expressions as 1 or 0 you can reduce the query further to this more compact form:
select
sum(sg_event = 'open') as `open_count`,
sum(sg_event = 'delivered') as `delivered_count`,
sum(sg_event = 'click') as `click_count`
from metrics

Related

Summing of count result at same level

I'm trying to sum the results of count(id) at the same level, in order to find out the relative portion of the count(id) from the overall count.
The count is grouped by the respective previous number, and I want to stay at the same table and have it all together.
`
select totalattempts, count(totalattempts) allattempts, count(case when success>0 then totalattempts else null end) successfulattempts
from (
select *, case when success> 0 then attemptspresuccess+1 else attemptspresuccess end totalattempts
from (select orderid, count(orderid) attemptspresuccess, count(case when recoveredPaymentId is not null then recoveredPaymentId end ) success from (
select orderid, recoveredPaymentId
from errors
where platform = 'woo'
) alitable
group by orderid) minitable ) finaltable
group by totalattempts
order by totalattempts asc
`
I need to add another column that basically would have, to put it simply, count(totalattempts)/sum(count(totalattempts).
I'm running out of ideas basically.
I can't use windows as this is an app of retool which doesn't support that
Assuming some test data here:
DECLARE #table TABLE (AttemptNumber INT IDENTITY, Success BIT)
INSERT INTO #table (Success) VALUES
(0),(0),(0),(0),(1),(1),(0),(0),(0),(0),(0),(1),(0),(1),(0),(0),
(0),(0),(1),(0),(0),(0),(0),(1),(0),(1),(0),(0),(0),(1),(0),(0)
I sounds like you want to know how many attempts there were, how many were successful and what that is a percentage?
SELECT COUNT(Success) AS TotalCount,
COUNT(CASE WHEN Success = 1 THEN 1 END) AS SuccessCount,
COUNT(CASE WHEN Success = 1.0 THEN 1 END)/(COUNT(Success)+.0) AS SuccessPct
FROM #table
TotalCount SuccessCount SuccessPct
--------------------------------------
32 8 0.2500000000000

SQL query to get percentages within a grouping

I've looked over similar questions and I just can't seem to get this right.
I have a table with three columns: ID, Date, and Method. None are unique.
I want to be able to see for any given date, how many rows match a certain pattern on Method.
So, for example, if the table has 100 rows, and 8 of them have the date "01-01-2020" and of those 8, two of them have a method of "A", I would want a return row that says "01-01-2020", "8", "2", and "25%".
My SQL is pretty rudimentary. I have been able to make a query to get me the count of each method by date:
select Date, count(*) from mytable WHERE Method="A" group by Date;
But I haven't been able to figure out how to put together the results that I am needing. Can someone help me out?
You could perform a count over a case expression for that method, and then divide the two counts:
SELECT date,
COUNT(*),
COUNT(CASE method WHEN 'A' THEN 1 END),
COUNT(CASE method WHEN 'A' THEN 1 END) / COUNT(*) * 100
FROM mytable
GROUP BY date
I'm assuming you're interested in all methods rather than just 'A', so you could do the following:
with ptotals as
(
SELECT
thedate,
count(*) as NumRows
FROM
mytable
group by
thedate
)
select
mytable.thedate,
mytable.themethod,
count(*) as method_count,
100 * count(*) / max(ptotals.NumRows) as Pct
from
mytable
inner join
ptotals
on
mytable.thedate = ptotals.thedate
group by
mytable.thedate,
mytable.themethod
You can use AVG() for the ratio/percentage:
SELECT date, COUNT(*),
SUM(CASE WHEN method = 'A' THEN 1 ELSE 0 END),
AVG(CASE WHEN method = 'A' THEN 100.0 ELSE 0 END)
FROM t
GROUP BY date;

Display the results in 1 row and different columns

Assume a simple case e.g. a table bug that has a column status that can be open,fixed etc.
If I want to know how many bugs are open I simply do:
select count(*) as open_bugs from bugs where status = 'open';
If I want to know how many bugs are open I simply do:
select count(*) as closed_bugs from bugs where status = 'closed';
If what want to know how many open and how many closed there are in a query that returns the results in 2 columns i.e.
Open | Closed|
60 180
What is the best way to do it? UNION concatenates the results so it is not what I want
This can be done by using a CASE expression with your aggregate function. This will convert the rows into columns:
select
sum(case when status = 'open' then 1 else 0 end) open_bugs,
sum(case when status = 'closed' then 1 else 0 end) closed_bugs
from bugs
This could also be written using your original queries:
select
max(case when status = 'open' then total end) open_bugs,
max(case when status = 'closed' then total end) closed_bugs
from
(
select status, count(*) as total from bugs where status = 'open' group by status
union all
select status, count(*) as total from bugs where status = 'closed' group by status
) d
Besides the CASE variants that aggregate over the whole table, there is another way. To use the queries you have and put them inside another SELECT:
SELECT
( SELECT COUNT(*) FROM bugs WHERE status = 'open') AS open_bugs,
( SELECT COUNT(*) FROM bugs WHERE status = 'closed') AS closed_bugs
FROM dual -- this line is optional
;
It has the advantage that you can wrap counts from different tables or joins in a single query.
There may also be differences in efficiency (worse or better). Test with your tables and indexes.
You can also use GROUP BY to get all the counts in separate rows (like the UNION you mention) and then use another aggregation to pivot the results in one row:
SELECT
MIN(CASE WHEN status = 'open' THEN cnt END) AS open_bugs,
MIN(CASE WHEN status = 'closed' THEN cnt END) AS closed_bugs
FROM
( SELECT status, COUNT(*) AS cnt
FROM bugs
WHERE status IN ('open', 'closed')
GROUP BY status
) AS g
Try this
select count(case when status = 'open' then 1 end) open_bugs,
count(case when status = 'closed' then 1 end) closed_bugs
from bugs

Using sum() to mimic count() of rows

I want to count the number of rows where a particular field = 'Q1'.
I usually use count(particular_field), but this does not allow me to count only when that field = 'Q1'.
Does the query SUM(particular_field = 'Q1') work for this matter? Or am I able to do count(particular_field = 'Q1')?
you can either do
select count(*)
from table
where particular_field = 'Q1'
or
select sum(case when particular_field ='Q1' then 1 else 0 end)
from table
You should be able to use a CASE statement with your SUM() (See SQL Fiddle)
SELECT SUM(CASE WHEN particular_field = 'Q1' THEN 1 ELSE 0 END) yourCount
FROM yourTable
Or (See SQL Fiddle) - this will give you a list of the count and each field. If you only want the one value, then use a WHERE clause to filter:
select count(*), particular_field
from yourTable
group by particular_field

SQL Select syntax error

thanks for your help yesterday.
I am now trying to incorporate the query from yesterday into an existing query so I can show the highest itemcode's reporting group in the existing query..but I have a syntax error somewhere at my Select statement.
ERROR: Keyword SELECT not expected.
I have tried putting brackets at every possible place but still no go..can you please help? (ps-this whole query has been giving me nightmares!)
WITH CALC1 AS (SELECT OTQUOT, OTIT01 AS ITEMS, ROUND(OQCQ01 * OVRC01,2) AS COST
FROM #LIB#.RTQOTA
WHERE OTIT01 <> ''
UNION ALL
SELECT OTQUOT, OTIT02 AS ITEMS, ROUND(OQCQ02 * OVRC02,2) AS COST
FROM #LIB#.RTQOTA
WHERE OTIT02 <> ''
UNION ALL
SELECT OTQUOT, OTIT03 AS ITEMS, ROUND(OQCQ03 * OVRC03,2) AS COST
FROM #LIB#.RTQOTA
WHERE OTIT03 <> ''
UNION ALL
SELECT OTQUOT, OTIT04 AS ITEMS, ROUND(OQCQ04 * OVRC04,2) AS COST
FROM #LIB#.RTQOTA
WHERE OTIT04 <> ''
UNION ALL
SELECT OTQUOT, OTIT05 AS ITEMS, ROUND(OQCQ05 * OVRC05,2) AS COST
FROM #LIB#.RTQOTA
WHERE OTIT05 <> ''
UNION ALL
SELECT OTQUOT, OTIT06 AS ITEMS, ROUND(OQCQ06 * OVRC06,2) AS COST
FROM #LIB#.RTQOTA
WHERE OTIT06 <> ''
UNION ALL
SELECT OTQUOT, OTIT07 AS ITEMS, ROUND(OQCQ07 * OVRC07,2) AS COST
FROM #LIB#.RTQOTA
WHERE OTIT07 <> ''
UNION ALL
SELECT OTQUOT, OTIT08 AS ITEMS, ROUND(OQCQ08 * OVRC08,2) AS COST
FROM #LIB#.RTQOTA
WHERE OTIT08 <> ''
UNION ALL
SELECT OTQUOT, OTIT09 AS ITEMS, ROUND(OQCQ09 * OVRC09,2) AS COST
FROM #LIB#.RTQOTA
WHERE OTIT09 <> ''
UNION ALL
SELECT OTQUOT, OTIT10 AS ITEMS, ROUND(OQCQ10 * OVRC10,2) AS COST
FROM #LIB#.RTQOTA
WHERE OTIT10 <> ''
)
(SELECT OTQUOT, DESC
FROM (
SELECT OTQUOT, ITEMS, B.IXRPGP AS GROUP, C.OTRDSC AS DESC, COST, ROW_NUMBER() OVER
(ORDER BY COST DESC) AS RN
FROM CALC1 AS A INNER JOIN #LIB#.ITMCON AS B ON (A.ITEMS = B.IKITMC) INNER JOIN
DATAGRP.GDSGRP AS C ON (B.IXRPGP = C.OKRPGP)
) T
WHERE T.RN >= 1)
SELECT
A.OKPBRN,
A.OCAREA,
A.OTCCDE,
A.OTCNAM,
A.OTSMAN,
A.OKPBRN||A.OAPNUM AS OTQUOT,
A.OTONUM,
A.OTCAD1,
A.OTCAD2,
A.OTCAD3,
A.OTPCDE,
A.OTDEL1,
A.OTDEL2,
A.OTDEL3,
CHAR(DATE(CASE WHEN SUBSTR(A.ODOQDT,5,4) = '0000' THEN '0001' ELSE SUBSTR(A.ODOQDT,5,4)
END ||'-'||
CASE WHEN SUBSTR(A.ODOQDT,4,2) = '00' THEN '01' ELSE SUBSTR(A.ODOQDT,3,2) END ||'-'||
CASE WHEN SUBSTR(A.ODOQDT,1,2) = '00' THEN '01' ELSE SUBSTR(A.ODOQDT,1,2) END), ISO) AS
ODOQDT_CCYYMMDD,
CHAR(DATE(CASE WHEN SUBSTR(A.ODDELD,7,2) = '' THEN '0001' ELSE '20'||SUBSTR(A.ODDELD,7,2)
END ||'-'||
CASE WHEN SUBSTR(A.ODDELD,4,2) = '' THEN '01' ELSE SUBSTR(A.ODDELD,4,2) END ||'-'||
CASE WHEN SUBSTR(A.ODDELD,1,2) = '' THEN '01' ELSE SUBSTR(A.ODDELD,1,2) END), ISO) AS
ODDELD_CCYYMMDD,
B.DESC,
A.OVQTVL
FROM
#LIB#.RTQCTL AS A INNER JOIN CALC1 AS B ON (A.OKPBRN||A.OAPNUM = B.OTQUOT)
WHERE
A.OKPBRN = '#OKPBRN#'
AND A.OTCCDE NOT LIKE '*DEP%'
AND CHAR(DATE(CASE WHEN SUBSTR(A.ODOQDT,5,4) = '0000' THEN '0001' ELSE SUBSTR
(A.ODOQDT,5,4) END ||'-'||
CASE WHEN SUBSTR(A.ODOQDT,4,2) = '00' THEN '01' ELSE SUBSTR(A.ODOQDT,3,2) END ||'-'||
CASE WHEN SUBSTR(A.ODOQDT,1,2) = '00' THEN '01' ELSE SUBSTR(A.ODOQDT,1,2) END), ISO) >=
CHAR(CURDATE() - 3 MONTH, ISO)
AND A.OCQF01 = '0'
AND A.OCQF02 = '0'
AND A.OCQF04 = '0'
AND A.OCQF05 = '0'
AND A.OCQF06 = '0'
AND A.OCQF07 = '0'
AND A.OCQF08 = '0'
AND A.OCQF09 = '0'
AND A.OCQF10 = '1'
AND A.OTCGRP LIKE 'S/%'
ORDER BY
A.OTSMAN ASC,
A.OVQTVL DESC,
CHAR(DATE(CASE WHEN SUBSTR(A.ODDELD,7,2) = '' THEN '0001' ELSE '20'||SUBSTR(A.ODDELD,7,2) END ||'-'||
CASE WHEN SUBSTR(A.ODDELD,4,2) = '' THEN '01' ELSE SUBSTR(A.ODDELD,4,2) END ||'-'||
CASE WHEN SUBSTR(A.ODDELD,1,2) = '' THEN '01' ELSE SUBSTR(A.ODDELD,1,2) END),ISO) ASC
When using UNION, wrap your SELECT statements in parentheses.
e.g.
(SELECT * FROM foo)
UNION ALL
(SELECT * FROM bar)
Edit: Upon closer inspection of that monstrosity of a query, there are likely numerous other errors within it. I suggest ripping parts of it out and provide us with the smallest possible example that still causes the syntax error.
It looks like you have two totally separate queries, with no semicolon between them.
This is where I think the problem is:
. . .
WHERE T.RN >= 1)
SELECT A.OKPBRN, A.OCAREA, A.OTCCDE, A.OTCNAM, A.OTSMAN,
. . .
It would really help when you ask questions to identify the brand and version of the database you're using. Different databases support different SQL language features, so the right solution depends strongly on the technology you're using. Tag your question with the brand you use.
There are many things wrong with your query:
MySQL does not support WITH common table expressions. This is what made me think you were using Oracle or Microsoft SQL Server when you asked another question related to this query yesterday.
MySQL does not support the ROW_NUMBER() windowing function. My apologies for suggesting you use this function, I had assumed you were using a database that supports WITH so I assumed ROW_NUMBER() would be supported too. You should learn to use the LIMIT clause if you use MySQL.
Trying to put a subquery that returns multiple columns and multiple rows into a single column of your select-list.
If you're trying to make the subquery part of the select-list, then SELECT belongs in front of the subquery. You should give it a column alias too.
Complex date-conversion expressions. I would recommend storing dates in a canonical ISO form.
The original design of OVRC01, OVRC02, OVRC03, etc. This is a repeating group, which violates First Normal Form. The same is true for OCQF01, OCQF02, OCQF03, etc.
I'm not sure you're using LIKE wildcards correctly. * is not a standard wildcard for LIKE.
Indecipherable table naming and column naming conventions. It looks like an Oracle database from the 1980's. Without knowing anything about your database or the problem you're trying to solve, it's impossible to recommend another solution.
It looks you have two CTE tables but only one is named. The second starts (SELECT OTQUOT, DESC(. You could name it (i.e., change it to , CALC2 As (SELECT OTQUOT, DESC(... but I haven't the foggiest idea where you are actually wanting to use this table in the rest of your query.