Query to display the % of the failure rate - mysql

I have written this query to get my data, and all the data is fine.
I have one column which has either Pass Or Fail. I want to calculate the % of number of bookings that failed, and output it in a single value.
I will have to write another query to show that one number.

Perhaps this? You didn't really offer much to go on:
SELECT
SUM(CASE
WHEN trip_rating.rating <= 3 OR
TIMESTAMPDIFF(MINUTE, booking_activity.activity_time, booking.pick_up_time) < 0
THEN 1.00 ELSE NULL END
) / COUNT(*)
FROM ...

Query
select
concat(
cast(
(
sum(case when t.Decision = 'Fail' then 1 else 0 end) / count(*)) * 100
as varchar(3)
), '%') as `fail rate`
from
(
select ........
case ........ end as Decision
)t;

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

mysql - possible to pivot across a dynamic date column?

consider the table
date
id
9/2
1
9/2
2
9/2
3
9/3
4
this can be pivoted up using count and case statements for each date
9/2
9/3
3
1
but is it possible to do the same thing without knowledge of the dates present in date column?
Yes, it is possible using the GROUP BY clause. As the clause name indicates, you can group the rows by a certain column or set of columns. You can combine that with the COUNT function to achieve your goal.
SELECT date, COUNT(*)
FROM TableName
GROUP BY date
If you are using MySQL v8 that supports recursive common table expression (cte), then you can combine that with prepared statement. I assume that the sample data you're provided in the question does not represent the real data you have especially the date format so let's say that your table is like this:
id
date
1
2022-09-02
2
2022-09-02
3
2022-09-02
4
2022-09-03
Whereby the date value is following the standard MySQL date format, here's a CREATE TABLE syntax:
CREATE TABLE testtable (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
date DATE);
Now, it seems like you know how to pivot the result using query so I assume it would look something like this:
SELECT SUM(CASE WHEN date="2022-09-02" THEN 1 ELSE 0 END) AS "2022-09-02",
SUM(CASE WHEN date="2022-09-03" THEN 1 ELSE 0 END) AS "2022-09-03"
FROM testtable;
If your query is nothing like the above then establish your own final structure of the query before you start. This will help you in shaping the query for the prepared statement.
The first step I'm doing here is generating the dynamic columns based on the date value. I'm using RECURSIVE cte here with the assumption that even skipped dates will still be shown as zeros:
WITH RECURSIVE cte AS (
SELECT MIN(date) AS mindt, MAX(date) AS maxdt
FROM testtable
UNION
SELECT mindt + INTERVAL 1 DAY, maxdt
FROM cte
WHERE mindt + INTERVAL 1 DAY <= maxdt)
SELECT * FROM cte
Based on your sample data, the result will return like this:
mindt
maxdt
2022-09-02
2022-09-16
2022-09-03
2022-09-16
The column that we will use for the rest of the process is just mindt. Column maxdt here is just for the cte reference on when to stop generating the running date.
Note: If you don't wish to show skipped dates then you don't need to use RECURSIVE cte and your final query should able to use on older MySQL versions as well. I'll include that option later in this answer.
Once we have that, we can start building our query for the prepared statement. Let's generate SUM(CASE WHEN date="2022-09-02" THEN 1 ELSE 0 END) AS "2022-09-02" (refer the final query above) from the RECURSIVE cte statement, so:
.....
SELECT CONCAT('SUM(CASE WHEN date="',mindt,'" THEN 1 ELSE 0 END) AS "',mindt,'"')
FROM cte
This is what you'll get from that:
CONCAT('SUM(CASE WHEN date="',mindt,'" THEN 1 ELSE 0 END) AS "',mindt,'"')
SUM(CASE WHEN date="2022-09-02" THEN 1 ELSE 0 END) AS "2022-09-02"
SUM(CASE WHEN date="2022-09-03" THEN 1 ELSE 0 END) AS "2022-09-03"
We'll do a GROUP_CONCAT() statement to make those results returned as a single row:
SELECT GROUP_CONCAT(CONCAT('SUM(CASE WHEN date="',mindt,'" THEN 1 ELSE 0 END) AS "',mindt,'"'))
FROM cte
This is what you'll get:
GROUP_CONCAT(CONCAT('SUM(CASE WHEN date="',mindt,'" THEN 1 ELSE 0 END) AS "',mindt,'"'))
SUM(CASE WHEN date="2022-09-02" THEN 1 ELSE 0 END) AS "2022-09-02",SUM(CASE WHEN date="2022-09-03" THEN 1 ELSE 0 END) AS "2022-09-03"
Now, the result above looks like the columns I'm aiming for the final query. I'll add another CONCAT() to add SELECT and FROM table_name like so:
...
SELECT CONCAT('SELECT ',
GROUP_CONCAT(
CONCAT('SUM(CASE WHEN date="',mindt,'" THEN 1 ELSE 0 END) AS "',mindt,'"')),
' FROM testtable;')
FROM cte;
This will return result of a query exactly the same as the one I'm aiming for my final query above. What I'll do next is just to insert the result of that into a variable and do the prepared statement operation. Let's say #sql is my variable:
SET #sql := NULL; /*setting as NULL just in case the variable is not empty*/
WITH RECURSIVE cte AS (
SELECT MIN(date) AS mindt, MAX(date) AS maxdt
FROM testtable
UNION
SELECT mindt + INTERVAL 1 DAY, maxdt
FROM cte
WHERE mindt + INTERVAL 1 DAY <= maxdt)
SELECT CONCAT('SELECT ',
GROUP_CONCAT(
CONCAT('SUM(CASE WHEN date="',mindt,'" THEN 1 ELSE 0 END) AS "',mindt,'"')),
' FROM testtable;') INTO #sql
FROM cte;
/*prepare, execute then deallocate the statement generated from #sql variable*/
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
The good thing about this is, if you're just adding data into the table and conditions are still the same - to pivot and count occurrence by date - you don't need to change the query at all.
Check this fiddle for more examples and explanation including the option to exclude skipped dates in the result.

How to write the a new select query with backward compatibility after adding a new column to a MySQL database

I have a MySQL table running for 4 months and I have a select statement in that table, like below.
SELECT
CONCAT(
YEAR(FROM_UNIXTIME(creation_time)),
'-',
IF(
MONTH(FROM_UNIXTIME(creation_time)) < 10,
CONCAT('0', MONTH(FROM_UNIXTIME(creation_time))),
MONTH(FROM_UNIXTIME(creation_time))
)
) AS Period,
(
COUNT(CASE
WHEN system_name = 'System' THEN 1
ELSE NULL
END)
) AS "Some data",
FROM table_name
GROUP BY
Period
ORDER BY
Period DESC
Lately, I've added a new feature and a column, let's say is_rerun. This value is just added and not exist previously. Now, i would like to write a query with the current statement which checks the system_name and also the is_rerun field and if this field exists and value is 1 then return 1 and if the column not exist or it its value is zero, then return null.
I tried IF EXISTS re_run THEN 1 ELSE NULL, but no luck. I can also insert values for the previous runs but i don't want to do that. Is there any solution. Thanks.
SELECT
CONCAT(
YEAR(FROM_UNIXTIME(creation_time)),
'-',
IF(
MONTH(FROM_UNIXTIME(creation_time)) < 10,
CONCAT('0', MONTH(FROM_UNIXTIME(creation_time))),
MONTH(FROM_UNIXTIME(creation_time))
)
) AS Period,
(
COUNT(CASE
WHEN system_name = 'System' AND IF EXISTS is_rerun THEN 1
ELSE NULL
END)
) AS "Some data",
FROM table_name
GROUP BY
Period
ORDER BY
Period DESC
As a starter: you have a group by query, so you need to put is_rerun in an aggregate function.
Based on your description, I think that something like case(case when is_rerun = 1 then 1 end) should do the work: it returns 1 if any is_rerun in the group is 1, else null.
Or if you can live with 0 instead of null, then you can use a simpler expression: max(is_rerun = 1).
Note that your query could be largely simplified as for the date formating logic and the conditional count. I would phrase it as:
select
date_format(from_unixtime(creation_time),'%Y-%m') period,
sum(system_name = 'System') some_data,
max(is_rerun = 1) is_rerun
from mytable
group by period
order by period desc

Get MAX,MIN,SUM,AVERAGE and create report from a single table

I am storing a flat file data from a text file with an Interval (let say hourly)
Data I am getting as below
Date (Datetime),
TotalTime(varchar(20)),
TotalCount(BigInt),
Minimum Time (varchar(20)),
Maximum Time (varchar(20)).
I am looking for a report such like
My SQL so far
select
sum(
(CASE WHEN (isnumeric(TotalTime) = 1)
THEN CAST(TotalTime AS bigint)
ELSE 0
END)
) as 'TotalTime',
sum(TotalCount) as 'TotalCount',
AVG(
(CASE WHEN (isnumeric(MinTime) = 1)
THEN CAST(MinTime AS bigint)
ELSE 0
END)
) as 'MinAvgTime',
AVG(
(CASE WHEN (isnumeric(MaxTime) = 1)
THEN CAST(MaxTime AS bigint)
ELSE 0
END)
) as 'MaxAvgTime',
dateadd(DAY,0, datediff(day,0, InputDate)) as created
from MYTABLE
group by dateadd(DAY,0, datediff(day,0, InputDate))
Trying to figure out is there any way I can get that output without using LINQ..Is there any way to get it directly from a SQL query
What result do you get from following SQL:
SELECT
date(`day`) AS created,
sum(TotalTime) AS TotalTime,
sum(TotalCount) AS TotalCount,
avg(MinTime) AS MinAvgTime,
avg(MaxTime) AS MaxAvgTime
FROM MYTABLE
GROUP BY 1;
I think this would work for you:
SELECT
CONVERT(DATE, InputDate, 103) as InputDate,
SUM(cast(TotalTime as int)) as TotalTime,
SUM(TotalCount) as TotalCount,
AVG(cast(MinTime as float)) as MinAvgTime,
AVG(cast(MaxTime as float)) as MaxAvgTime
FROM
MYTABLE
GROUP BY
CONVERT(DATE, InputDate, 103)
Use a view or CTE function and can be query from SQL directly

Optimize SQL Server Query

I have to do a query to get the total cost of previous month and compared to current month to calculate the percentage difference.
this is the script:
create table #calc
(
InvoiceDate Date,
TotalCost decimal (12,2)
)
insert into #calc values ('2013-07-01', 9470.36)
insert into #calc values ('2013-08-01', 11393.81)
and this is the query:
select InvoiceDate,
TotalCost,
PrevTotalCost,
(CASE WHEN (PrevTotalCost = 0)
THEN 0
ELSE (((TotalCost - PrevTotalCost) / PrevTotalCost) * 100.0)
END) AS PercentageDifference
from (
select a.InvoiceDate, a.TotalCost,
isnull((select b.TotalCost
from #calc b
where InvoiceDate = (select MAX(InvoiceDate)
from #calc c
where c.InvoiceDate < a.InvoiceDate)), 0) as PrevTotalCost
from #calc a) subq
Is there a more efficient way to do it for cgetting the previous month?
Using a ranking function to put more burden on sorts than table scans seems the fastest when using no indexes. The query below processed 6575 records in under a second:
SELECT
Main.InvoiceDate,
Main.TotalCost,
PreviousTotalCost=Previous.TotalCost,
PercentageDifference=
CASE WHEN COALESCE(Previous.TotalCost,0) = 0 THEN 0
ELSE (((Main.TotalCost - Previous.TotalCost) / Previous.TotalCost) * 100.00)
END
FROM
(
SELECT
InvoiceDate,
TotalCost,
OrderInGroup=ROW_NUMBER() OVER (ORDER BY InvoiceDate DESC)
FROM
Test
)AS Main
LEFT OUTER JOIN
(
SELECT
InvoiceDate,
TotalCost,
OrderInGroup=ROW_NUMBER() OVER (ORDER BY InvoiceDate DESC)
FROM
Test
)AS Previous ON Previous.OrderInGroup=Main.OrderInGroup+1
Using nested looping as the case when getting the previous invoice cost in a select subquery proves the slowest - 6575 rows in 30 seconds.
SELECT
X.InvoiceDate,
X.TotalCost,
X.PreviousTotalCost,
PercentageDifference=
CASE WHEN COALESCE(X.PreviousTotalCost,0) = 0 THEN 0
ELSE (((X.TotalCost - X.PreviousTotalCost) / X.PreviousTotalCost) * 100.00)
END
FROM
(
SELECT
InvoiceDate,
TotalCost,
PreviousTotalCost=(SELECT TotalCost FROM Test WHERE InvoiceDate=(SELECT MAX(InvoiceDate) FROM Test WHERE InvoiceDate<Main.InvoiceDate))
FROM
Test AS Main
)AS X
Your query processed 6575 records in 20 seconds with the biggest cost coming from the nested loops for inner join
select InvoiceDate,
TotalCost,
PrevTotalCost,
(CASE WHEN (PrevTotalCost = 0)
THEN 0
ELSE (((TotalCost - PrevTotalCost) / PrevTotalCost) * 100.0)
END) AS PercentageDifference
from (
select a.InvoiceDate, a.TotalCost,
isnull((select b.TotalCost
from Test b
where InvoiceDate = (select MAX(InvoiceDate)
from #calc c
where c.InvoiceDate < a.InvoiceDate)), 0) as PrevTotalCost
from Test a) subq
Using indexes would be a big plus unless you are required to use temp tables.
Hope this helps :)
SELECT
`current`.`InvoiceDate`,
`current`.`TotalCost`,
`prev`.`TotalCost` AS `PrevTotalCost`,
(`current`.`TotalCost` - `prev`.`TotalCost`) AS `CostDifference`
FROM dates `current`
LEFT JOIN
dates `prev`
ON `prev`.`InvoiceDate` <= DATE_FORMAT(`current`.`InvoiceDate` - INTERVAL 1 MONTH, '%Y-%m-01');
Screenshot of the results I got: http://cl.ly/image/0b3z2x1f2H1n
I think this might be what you're looking for.
Edit: I wrote this query in MySQL, so it's possible you may need to alter a couple minor syntax things for your server.