Summing of count result at same level - mysql

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

Related

Calculating consecutive occurences in MySQL

I have a quick question in relation to windowing in MySQL
SELECT
Client,
User,
Date,
Flag,
lag(Date) over (partition by Client,User order by Date asc) as last_date,
lag(Flag) over (partition by Client,User order by Date asc) as last_flag,
case when Flag = 1 and last_flag = 1 then 1 else 0 end as consecutive
FROM db.tbl
This query returns something like the below. I am trying to work out the number of consecutive times that the Flag column was 1 for each user most recently, if they had 11110000111 then we should take the final three occurences of 1 to determine that they had a consecutive flag of 3 times.
I need to extract the start and end date for the consecutive flag.
How would I go about doing this, can anyone help me :)
If we use the example of 11110000111 then we should extract only 111 and therefore the 3 most recent dates for that customer. So in the below, we would need to take 10.01.2023 as the first date and 24.01.2023 as the last date. The consecutive count should be 3
Output:
Use aggregation and string functions:
WITH cte AS (
SELECT Client, User,
GROUP_CONCAT(CASE WHEN Flag THEN Date END ORDER BY Date) AS dates,
CHAR_LENGTH(SUBSTRING_INDEX(GROUP_CONCAT(Flag ORDER BY Date SEPARATOR ''), '0', '-1')) AS consecutive
FROM tablename
GROUP BY Client, User
)
SELECT Client, User,
NULLIF(SUBSTRING_INDEX(SUBSTRING_INDEX(dates, ',', -consecutive), ',', 1), '') AS first_date,
CASE WHEN consecutive > 0 THEN SUBSTRING_INDEX(dates, ',', -1) END AS last_date,
consecutive
FROM cte;
Another solution with window functions and conditional aggregation:
WITH
cte1 AS (SELECT *, SUM(NOT Flag) OVER (PARTITION BY Client, User ORDER BY Date) AS grp FROM tablename),
cte2 AS (SELECT *, MAX(grp) OVER (PARTITION BY Client, User) AS max_grp FROM cte1)
SELECT Client, User,
MIN(CASE WHEN Flag THEN Date END) AS first_date,
MAX(CASE WHEN Flag THEN Date END) AS last_date,
SUM(Flag) AS consecutive
FROM cte2
WHERE grp = max_grp
GROUP BY Client, User;
See the demo.
Made an attempt to get the result with more simpler queries and here is my approach taking advantage of lastDate and lastFlag column too.
Run here
WITH eTT
AS
( SELECT Client, User, NULLIF(MAX(Date),
(SELECT MAX(Date) FROM tt t2 WHERE t1.Client=t2.Client AND t1.User=t2.User)) as endDate
FROM tt t1 WHERE LastFlag=0 OR LastFlag IS NULL GROUP BY Client, User
)
SELECT Client, User,
(CASE WHEN MAX(endDate) IS NULL THEN NULL ELSE MIN(Date) END) as first_date,
(CASE WHEN MAX(endDate) IS NULL THEN NULL ELSE MAX(Date) END) as last_date,
(CASE WHEN MAX(endDate) IS NULL THEN NULL ELSE COUNT(endDate) END) as consecutive
FROM tt LEFT JOIN eTT USING (Client, User)
WHERE Date >= endDate OR endDate IS null GROUP BY Client, User;
EDIT
The original table doesn't have LastDate and LastFlag columns and were created using OP's initial query.
Since the method used is not apparantly supported but I get an impression that OP somehow manages to do that on their side.
Hence another cte called tt can be added before eTT containing that query.

Mysql group by and sum two different columns

I have this table called transactions, where agents can give certain amounts to other agents, we have 2 columns, one called agent_from which is the agent that put the amount and agent_to is the one reciving the amount.
An example with the id 1 would be that the agent2 is giving an amount of 300 to the agent8
The report that I would like to do is a sum and a group by agent_from and agent_to
Right now I am able to make the query separatly like this
SELECT agent_from,
SUM(amount) as from_transaccions
FROM `transactions` GROUP BY agent_from;
This would give me this result:
This return a sum of all the amounts made by agent_from.
Now I can repeat this query changing the column name from agent_from to agent_to so I can get the sum of all the amounts recived by agent_to, that will look like this:
An example would be that the agent8 recived 2 transaccions (300 + 450) = 750
Now what I want to do is make this 2 querys into one that will look like this:
Refer query below -
with data_cte as (
(select agent_from agent, amount, 'af' flag from transactions) union all
(select agent_to agent, amount, 'at' flag from transactions)
)
select agent,
sum(case when flag='af' then amount else 0 end) from_sum,
sum(case when flag='at' then amount else 0 end) to_sum
from data_cte
group by agent
union all
select 'total' as col1,
sum(case when flag='af' then amount else 0 end) from_sum,
sum(case when flag='at' then amount else 0 end) to_sum
from data_cte
group by col1
order by agent
fiddle.
Use UNION ALL to split each row of the table to 2 rows so that you separate the 2 agents and aggregate:
SELECT COALESCE(agent, 'total') agent,
SUM(`from`) `from`,
SUM(`to`) `to`
FROM (
SELECT agent_from agent, amount `from`, 0 `to` FROM `transactions`
UNION ALL
SELECT agent_to, 0 `from`, amount `to` FROM `transactions`
) t
GROUP BY agent WITH ROLLUP
ORDER BY GROUPING(agent);
See the demo.

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;

req_type wise count id in one query

I have an sql query problem . I don't want to execute three times query for same result.
In my table I have one field req_type which have three parameter ,
either 1, either 2, either 3 .
I want counter based on req_type in one query instead of by executing query 3 times like below
select count(id) as premium FROM tablename where req_type=1
select count(id) as premium1 FROm tablename where req_type=2
select count(id) as premium2 FROm tablename where req_type=3
I am stuck , can anybody help me?
You could use case for such type of count
select sum(case when req_type=1 then 1 else 0 end) as premium,
sum(case when req_type=2 then 1 else 0 end) as premium1,
sum(case when req_type=3 then 1 else 0 end) as premium2
FROM tablename
Use one query instead of threes by using group by cluase
select req_type , count(id) as premium
FROM tablename
where req_type in (1,2,3)
group by req_type
Use a GROUP BY
SELECT req_type, COUNT(id) AS count_premium
FROM tablename
GROUP BY req_type;

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