mysql address outer query from subquery - mysql

I have this query:
SELECT
sec_to_time(avg(t1.sessiontime)) as aloc,
CONCAT(TRUNCATE(sum(t1.terminatecauseid = 1) * 100 / count(*),
1),
'%') as asr,
count(*) as calls,
cast(t1.destination as unsigned) as prefix,
t2.destination as destination,
SEC_TO_TIME(sum(t1.sessiontime)) as duration
FROM
cc_call AS t1
inner join
cc_prefix as t2 ON t1.destination = t2.prefix
WHERE
t1.card_id = '133' AND t1.starttime >= ('2014-06-1') AND t1.starttime <= ('2014-07-01 23:59:59') and t1.terminatecauseid = 1
group by t1.destination
order by duration DESC
LIMIT 0 , 25
t1.terminatecauseid = 1 means successful call,
'asr' means average success rate,
Im trying to find out how many calls with (t1.terminatecauseid = 1) from the total calls made to an extension.
this line doesn't work:
sum(t1.terminatecauseid = 1) * 100 / count(*)
since I already have (t1.terminatecauseid = 1) in the WHERE clause.
Im thinking about putting a subquery, to retrieve total calls, where count(*) currently is.
How can I have this query calculate the ASR with total calls made?
example sqlfiddle
if possible, I'd like to not show results with duration=NULL

Use conditional aggregation, something like this:
SELECT sec_to_time(avg(case when t1.terminatecauseid = 1 then t1.sessiontime end)) as aloc,
CONCAT(TRUNCATE(sum(t1.terminatecauseid = 1) * 100 / count(*),
1),
'%') as asr,
count(*) as TotalCalls,
sum(t1.terminatecauseid = 1) as Terminated1Calls,
cast(t1.destination as unsigned) as prefix,
t2.destination as destination,
SEC_TO_TIME(sum(case when t1.terminatecauseid = 1 then t1.sessiontime end)) as duration
FROM cc_call t1 inner join
cc_prefix t2
ON t1.destination = t2.prefix
WHERE t1.card_id = '133' AND
t1.starttime >= ('2014-06-1') AND t1.starttime <= ('2014-07-01 23:59:59')
group by t1.destination
order by duration DESC
LIMIT 0 , 25;

Related

MySQL duration for 9 rows, that's my code

SELECT DATE_FORMAT(b.checktime,"%Y-%m-%d") AS dtDate,
case when (
SELECT DATE_FORMAT(a.checktime,'%H:%i:%s')
FROM checkinout a
WHERE a.checktype='0'
and a.userid=1
and DATE_FORMAT(a.checktime,'%Y-%m-%d')=DATE_FORMAT(b.checktime,'%Y-%m-%d')
LIMIT 1)
is not NULL
then
(
SELECT
DATE_FORMAT(a.checktime,'%H:%i:%s')
FROM checkinout a
WHERE a.checktype='0'
and a.userid=1
and DATE_FORMAT(a.checktime,'%Y-%m-%d')=DATE_FORMAT(b.checktime,'%Y-%m-%d')
LIMIT 1
)
else 'N/A' END
AS Chkin
from checkinout b
where
DATE_FORMAT(b.checktime,"%m")='06' AND
DATE_FORMAT(b.checktime,"%Y")='2019' AND
DATE_FORMAT(b.checktime,"%w")!='0' AND .
DATE_FORMAT(b.checktime,"%w")!='6' AND .
DATE_FORMAT(b.checktime,"%Y-%m-%d") not in
(select date_s from wend)
GROUP BY dtDate
ORDER BY dtDate DESC
Affected rows: 0 Found rows: 9 Warnings: 0 Duration for 1 query: 25.665 sec.
what's wrong with this query, for 9 rows need 25.665 seconds
Thanks
Without understanding the purpose of the query, it can be rewritten to:
SELECT DISTINCT date(b.checktime) AS dtDate,
coalesce((
SELECT time(a.checktime)
FROM checkinout a
WHERE a.checktype = '0'
and a.userid = 1
and date(a.checktime) = date(b.checktime)
LIMIT 1
), 'N/A') AS Chkin
from checkinout b
where month(b.checktime) = 6
AND year(b.checktime) = 2019
AND weekday(b.checktime) not in (5, 6) -- non weekend
AND date(b.checktime) not in (select date_s from wend)
ORDER BY dtDate DESC
Though GROUP BY might perform better than DISTINCT - You should test both. However, the above query can be optimized to use indexes.
The outer condition month(b.checktime) = 6 AND year(b.checktime) = 2019 can be rewritten to b.checktime >= '2019-06-01' AND b.checktime < '2019-06-01' + INTERVAL 1 MONTH. This way the engine should be able to use an index on (checktime).
The condition date(a.checktime) = date(b.checktime) can be written as a.checktime >= date(b.checktime) and a.checktime < date(b.checktime) + INTERVAL 1 DAY. Here I suggest one of the following indexes: (checktype, userid, checktime), (userid, checktype, checktime) or (userid, checktime).
And for date(b.checktime) not in (select date_s from wend) it might be better to use an "anti-join".
So here is the final query, which I would try:
SELECT DISTINCT date(b.checktime) AS dtDate,
coalesce((
SELECT time(a.checktime)
FROM checkinout a
WHERE a.checktype = '0'
and a.userid = 1
and a.checktime >= date(b.checktime)
and a.checktime < date(b.checktime) + INTERVAL 1 DAY
LIMIT 1
), 'N/A') AS Chkin
from checkinout b
LEFT JOIN wend w ON w.date_s = date(b.checktime)
where b.checktime >= '2019-06-01'
AND b.checktime < '2019-06-01' + INTERVAL 1 MONTH
AND weekday(b.checktime) not in (5, 6) -- non weekend
AND w.date_s IS NULL
ORDER BY dtDate DESC

Why integer cast is not working with integer group_concat() list?

I'm stuck at the query where I need to concat IDs of the table. And from that group of IDs, I need to fetch that rows in sub query. But when I try to do so, MySQL consider group_concat() as a string. So that condition becomes false.
select count(*)
from rides r
where r.ride_status = 'cancelled'
and r.id IN (group_concat(rides.id))
*************** Original Query Below **************
-- Daily Earnings for 7 days [Final]
select
group_concat(rides.id) as ids,
group_concat(ride_category.name) as rideType,
group_concat(ride_cars.amount + ride_cars.commission) as rideAmount ,
group_concat(ride_types.name) as carType,
count(*) as numberOfRides,
(
select count(*) from rides r where r.ride_status = 'cancelled' and r.id IN (group_concat(rides.id) )
) as cancelledRides,
(
select count(*) from rides r where r.`ride_status` = 'completed' and r.id IN (group_concat(rides.id))
) as completedRides,
group_concat(ride_cars.status) as status,
sum(ride_cars.commission) + sum(ride_cars.amount) as amount,
date_format(from_unixtime(rides.requested_at/1000 + rides.offset*60), '%Y-%m-%d') as requestedDate,
date_format(from_unixtime(rides.requested_at/1000 + rides.offset*60), '%V') as week
from
ride_cars,
rides,
ride_category,
ride_type_cars,
ride_types
where
ride_cars.user_id = 166
AND (rides.ride_status = 'completed' or. rides.ride_status = 'cancelled')
AND ride_cars.ride_id = rides.id
AND (rides.requested_at >= 1559347200000 AND requested_at < 1561852800000)
AND rides.ride_category = ride_category.id
AND ride_cars.car_model_id = ride_type_cars.car_model_id
AND ride_cars.ride_type_id = ride_types.id
group by
requestedDate;
Any solutions will be appreciated.
Try to replace the sub-query
(select count(*) from rides r where r.ride_status = 'cancelled' and r.id IN (group_concat(rides.id) )) as cancelledRides,
with below to count using SUM and CASE, it will make use of the GROUP BY
SUM(CASE WHEN rides.ride_status = 'cancelled' THEN 1 ELSE 0 END) as cancelledRides
and the same for completedRides
And move to using JOIN instead of implicit joins

user defined variable to store ranking gives wrong values if order by

mysql table: work
|id|user_id|created_at|realization|
I have been working on a sql query which calculates performance (realisation today / realization on the first day of the month) and sortes records based on performance.
Expected result:
|ranking|performance|user|
|1|0.88|36|
|2|0.712444111|444|
|3|0.711|1|
|4|0.33333|9|
|5|0.1006|29|
returned result:
|ranking|performance|user|
|4|0.88|36|
|2|0.712444111|444|
|5|0.711|1|
|3|0.33333|9|
|1|0.1006|29|
Here is my query:
SET #ranking := 0;
SELECT
#ranking := #ranking + 1 as ranking,
w1.user_id,
IFNULL(ROUND(w2.realization / w1.realization), 4), 0) AS performance
FROM work w1
JOIN (
SELECT min(created_at) AS first_month, max(created_at) AS last_month, user_id
FROM work
WHERE (DATE_FOMAT(NOW(), '%Y-%m') = DATE_FORMAT(created_at, '%Y-%m')
GROUP BY user_id
ORDER BY user_id
) AS w ON w1.user_id = w.user_id AND w1.created_at = w.first_month
JOIN work AS w2 ON w1.user_id = w2.user_id AND w2.created_at = w.last_month
ORDER BY performance DESC
UPDATE
Even if I try to wrap it this way, the rankings are not right
SET #ranking := 0;
SELECT #ranking := #ranking + 1 as ranking, a.user_id, a.performance
FROM (
SELECT
w1.user_id,
IFNULL(ROUND(w2.realization / w1.realization), 4), 0) AS performance
FROM work w1
JOIN (
SELECT min(created_at) AS first_month, max(created_at) AS last_month, user_id
FROM work
WHERE (DATE_FOMAT(NOW(), '%Y-%m') = DATE_FORMAT(created_at, '%Y- %m')
GROUP BY user_id
ORDER BY user_id
) AS w ON w1.user_id = w.user_id AND w1.created_at = w.first_month
JOIN work AS w2 ON w1.user_id = w2.user_id AND w2.created_at = w.last_month
ORDER BY performance DESC
) AS a

can you please help in tuning the query

This query takes around 45s to 1 min for 25000 records.I need an alternative to case
condition for expirydate field
SELECT a.id,
a.name,
a.lastname,
a.plainpass,
a.email,
a.custom_usertype,
a.custom_registertype,
a.content_state,
a.year,
a.bflag,
a.block,
a.trail_expiry,
a.subscribe_date,
CASE a.custom_usertype
WHEN (5)
THEN
(IF(
(SELECT custom_usertype
FROM skw_users
WHERE id = a.parent_id AND custom_usertype = 11) = 11
AND a.custom_registertype = "subscribed",
(SELECT DATE_FORMAT(prod.expiry_date, "%Y-%m-%d")
FROM skw_product prod
WHERE prod.student_id = a.id
ORDER BY prod.expiry_date DESC
LIMIT 1),
IF(
(SELECT custom_usertype
FROM skw_users
WHERE id = a.parent_id AND custom_usertype = 10) =
10
AND a.custom_registertype = "subscribed",
(SELECT DATE_FORMAT(prod.expiry_date, "%Y-%m-%d")
FROM skw_product prod
WHERE prod.User_id = a.parent_id
ORDER BY prod.expiry_date DESC
LIMIT 1),
(SELECT DATE_FORMAT(trail_expiry, "%Y-%m-%d")
FROM skw_users
WHERE id = a.parent_id))))
WHEN (3)
THEN
(IF(a.custom_registertype = "subscribed",
(SELECT DATE_FORMAT(prod.expiry_date, "%Y-%m-%d")
FROM skw_product prod
WHERE prod.User_id = a.parent_id
ORDER BY prod.expiry_date DESC
LIMIT 1),
(SELECT DATE_FORMAT(trail_expiry, "%Y-%m-%d")
FROM skw_users
WHERE id = a.parent_id)))
ELSE
(IF(a.custom_registertype = "subscribed",
(SELECT DATE_FORMAT(prod.expiry_date, "%Y-%m-%d")
FROM skw_product prod
WHERE prod.User_id = a.id
ORDER BY prod.expiry_date DESC
LIMIT 1),
(SELECT DATE_FORMAT(trail_expiry, "%Y-%m-%d")
FROM skw_users
WHERE id = a.id)))
END
AS expiry_date_n,
CASE a.custom_usertype
WHEN (5)
THEN
(SELECT TRIM(NAME)
FROM skw_users
WHERE id = a.parent_id AND custom_usertype = 10)
WHEN (3)
THEN
(SELECT TRIM(NAME)
FROM skw_users
WHERE id = a.parent_id)
WHEN (10)
THEN
(SELECT TRIM(NAME)
FROM skw_users
WHERE id = a.id AND a.custom_usertype = 10)
END
AS schoolname
FROM `skw_users` AS a
INNER JOIN
skw_user_usergroup_map AS map2
ON map2.user_id = a.id
WHERE map2.group_id = 2
GROUP BY a.id
ORDER BY trim(a.name) ASC
This query takes around 45s to 1 min for 25000 records.I need an alternative to case
condition for expirydate field
Try adding index on Primary Key column that is a.id and the column on which you are applying case that is a.custom_usertype
Hope this will speed up the execution of query :)

MYSQL Query with Multiple Selects from Same Table

Getting an error
Operand should contain 1 column(s)
PK is ID
The table just dumps data in to the table
need to get the earliest date qty and the latest date qty and display on the same column
Any help appreciated
SELECT ebx_r_history.ItemNumber,
(SELECT r.QuantitySold as newqty, r.lastupdate as lu
FROM ebx_r_history r
WHERE ebx_r_history.ItemNumber = r.ItemNumber AND ebx_r_history.SKU = r.SKU
ORDER BY r.LastUpdate ASC
LIMIT 1),
(SELECT r.QuantitySold as newqty, r.lastupdate as lu
FROM ebx_r_history r
WHERE ebx_r_history.ItemNumber = r.ItemNumber AND ebx_r_history.SKU = r.SKU
ORDER BY r.LastUpdate DESC
LIMIT 1)
FROM
ebx_r_history
GROUP BY ebx_r_history.ItemNumber,
ebx_r_history.SKU
ORDER BY ebx_r_history.LastUpdate
This version may offer a simplified and faster alternative for you. The inner query for "AllItems" does both a min and max of the last update on a per-item number/sku basis, although I believe they would be one-in-the-same record.
So now, join that results back to the history data by item/sku and only those that match either the min or max date. If a true date/time, there would expect to only be one anyhow, vs just a date-only. So, since there would be 2 possible records (one for the min, one for the max), I am applying a MAX( IIF( )) for each respective matching the minimum and maximum dates respectively and must retain the group by clause.
Note, if you are dealing with date-only entries, or possibilities of the exact same item/sku and lastupdate are the same to the second, then you would need an approach more towards limit 1 per ascending/descending basis.
SELECT
AllItems.ItemNumber,
AllItems.SKU,
AllItems.MinUpdate,
MAX( IIF( rh.lastupdate = AllItems.MinUpdate, rh.Quantity.Sold, 0 )) as QtyAtMinDate,
AllItems.MaxUpdate,
MAX( IIF( rh.lastupdate = AllItems.MaxUpdate, rh.Quantity.Sold, 0 )) as QtyAtMaxDate
from
( SELECT
r.ItemNumber,
r.SKU,
MIN( r.lastupdate ) as MinUpdate,
MAX( r.lastupdate ) as MaxUpdate
FROM
ebx_r_history r
group by
r.ItemNumber,
r.SKU ) AllItems
JOIN ebx_r_history rh
ON AllItems.ItemNumber = rh.ItemNumber
AND AllItems.SKU = rh.SKU
AND ( rh.lastUpdate = AllItems.MinUpdate
OR rh.lastUpdate = AllItems.MaxUpdate )
group by
AllItems.ItemNumber,
AllItems.SKU
Per another answer where you were only looking to IGNORE items within the most recent 14 days, you can just add a WHERE clause to the inner query similar via
WHERE r.LastUpdate >= CURDATE() - INTERVAL 14 DAY
If your history table has an auto-incrementing ID column, AND the respective transactions have the lastUpdate sequentially stamped, such as when they are added and not modified by any other operation, then you could just apply similar but MIN/MAX of the ID column, then join back TWICE on the ID and just each row ONCE such as...
SELECT
AllItems.ItemNumber,
AllItems.SKU,
rhMin.LastUpdate as MinUpdate,
rhMin.QuantitySold as MinSold,
rhMax.LastUpdate as MaxUpdate,
rhMax.QuantitySold as MaxSold
from
( SELECT
r.ItemNumber,
r.SKU,
MIN( r.AutoIncrementColumn ) as MinAutoID,
MAX( r.AutoIncrementColumn ) as MaxAutoID
FROM
ebx_r_history r
group by
r.ItemNumber,
r.SKU ) AllItems
JOIN ebx_r_history rhMin
ON AllItems.MinAutoID = rhMin.AutoIncrementColumn
JOIN ebx_r_history rhMax
ON AllItems.MaxAutoID = rhMax.AutoIncrementColumn
order by
rhMax.LastUpdated
Try something like this:
SELECT r1.ItemNumber,
(
SELECT r.QuantitySold
FROM ebx_r_history r
WHERE r1.ItemNumber = r.ItemNumber
AND r1.SKU = r.SKU
ORDER BY r.LastUpdate ASC LIMIT 1
) AS earliestDateQty,
(
SELECT r.QuantitySold
FROM ebx_r_history r
WHERE r1.ItemNumber = r.ItemNumber
AND r1.SKU = r.SKU
ORDER BY r.LastUpdate DESC LIMIT 1
) AS latestDateQty
FROM ebx_r_history r1
GROUP BY r1.ItemNumber,r1.SKU
ORDER BY 3
You had a couple of errors. you were getting two columns inside the inner selects, and you had a couple of places where you might get the error for ambiguous column name.
sqlFiddle here
SELECT T1.ItemNumber,
T1.SKU,
T1.Old_QuantitySold,
T1.Old_LastUpdate,
T2.New_QuantitySold,
T2.New_LastUpdate
FROM
(SELECT itemNumber,SKU,QuantitySold as Old_QuantitySold,LastUpdate as Old_LastUpdate
FROM ebx_r_history r
WHERE NOT EXISTS (SELECT 1 FROM ebx_r_history e
WHERE e.itemNumber = r.itemNumber AND e.SKU = r.SKU
AND e.LastUpdate < r.LastUpdate)
)T1
LEFT JOIN
(SELECT itemNumber,SKU,QuantitySold as New_QuantitySold,LastUpdate as New_LastUpdate
FROM ebx_r_history r
WHERE NOT EXISTS (SELECT 1 FROM ebx_r_history e
WHERE e.itemNumber = r.itemNumber AND e.SKU = r.SKU
AND e.LastUpdate > r.LastUpdate)
)T2 ON (T2.itemNumber = T1.itemNumber AND T2.SKU = T1.SKU)
WHERE T1.Old_LastUpdate >= CURDATE() - INTERVAL 14 DAY
AND T2.New_LastUpdate >= CURDATE() - INTERVAL 14 DAY
ORDER BY T2.New_LastUpdate;
you can do left join or inner join it's up to you, since T1 will always get earliest records and T2 will always get latest records for the ItemNumber,SKU grouping.
UPDATED TO IGNORE DATA OLDER THAN 14 DAYS
SELECT T1.ItemNumber,
T1.SKU,
T1.Old_QuantitySold,
T1.Old_LastUpdate,
T2.New_QuantitySold,
T2.New_LastUpdate
FROM
(SELECT itemNumber,SKU,QuantitySold as Old_QuantitySold,LastUpdate as Old_LastUpdate
FROM ebx_r_history r
WHERE LastUpdate >= CURDATE() - INTERVAL 14 DAY
AND NOT EXISTS (SELECT 1 FROM ebx_r_history e
WHERE e.itemNumber = r.itemNumber AND e.SKU = r.SKU
AND e.LastUpdate >= CURDATE() - INTERVAL 14 DAY
AND e.LastUpdate < r.LastUpdate)
)T1
LEFT JOIN
(SELECT itemNumber,SKU,QuantitySold as New_QuantitySold,LastUpdate as New_LastUpdate
FROM ebx_r_history r
WHERE LastUpdate >= CURDATE() - INTERVAL 14 DAY
AND NOT EXISTS (SELECT 1 FROM ebx_r_history e
WHERE e.itemNumber = r.itemNumber AND e.SKU = r.SKU
AND e.LastUpdate >= CURDATE() - INTERVAL 14 DAY
AND e.LastUpdate > r.LastUpdate)
)T2 ON (T2.itemNumber = T1.itemNumber AND T2.SKU = T1.SKU)
ORDER BY T2.New_LastUpdate;
ignore data older than 14 days sqlFiddle here
If you want to use exact time (14 days ago), you can replace occurences of CURDATE() with NOW()