MySQL duration for 9 rows, that's my code - mysql

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

Related

MySQL query with WHERE subquery does not work on no result

I have written a complex query in MySQL to return a result.
it works perfectly
Until .....
the subquery returns no result
how to write an if or IF null then substitute in date '2020-06-03'
any help greatly appreciated
SELECT
*
FROM
trades
WHERE
stock_code = 'IHVV'
AND acc_id = '4'
AND tx_date >
(SELECT tx_date
FROM
( SELECT *, ( #sum_units := #sum_units + units ) AS sum_units
FROM
trades
JOIN ( SELECT #sum_units := 0 ) params
WHERE
stock_code = 'IHVV'
AND acc_id = '4'
AND tx_date <= '2021-06-30'
AND ( transfer_date IS NULL OR transfer_date <= '2021-06-30' )
ORDER BY
tx_date ASC,
units ASC
) AS query1
WHERE
tx_date < DATE_SUB( '2021-06-30', INTERVAL 1 YEAR )
AND sum_units = 0
ORDER BY
tx_date DESC
LIMIT 1
)
AND tx_date <= '2021-06-30'
AND ( transfer_date IS NULL OR transfer_date <= '2021-06-30' )
ORDER BY
tx_date ASC,
units ASC
clarification
I have written a main query and in one of the where clauses I am using a subquery and this subquery works well, until this subquery does not return a result and my main query stops working, so I would like to on no result in this subquery substitute a value on no result so the main query can function normally
example needed
select * from table where date > (ifnull(subquery, "2002-01-01"))
I get
incorrect parameter count in the call to native function "IFNULL'
AND THE ANSWER IS: ---> :)
thanks guys for all your suggestions
much appreciated
SELECT *
FROM trades
WHERE stock_code = 'IHVV'
AND acc_id = '4'
AND tx_date >
#last 0 date out of 1 year perhaps change the date range by from date and to date in the interval 1 year area
(SELECT COALESCE(
(SELECT tx_date
FROM (SELECT *, (#sum_units := #sum_units + units) AS sum_units
FROM trades
JOIN ( SELECT #sum_units := 0 ) params
WHERE stock_code = 'ANZ'
AND acc_id = '4'
AND tx_date <= '2022-06-30'
AND (transfer_date IS NULL OR transfer_date <= '2022-06-30' ))
ORDER BY tx_date ASC, units ASC) as query1
WHERE tx_date < DATE_SUB('2022-06-30',INTERVAL 1 YEAR)
AND sum_units = 0
ORDER BY tx_date DESC
LIMIT 1), 'TODATE')
AND tx_date <= '2022-06-30'
AND (transfer_date IS NULL OR transfer_date <= '2022-06-30' )
ORDER BY tx_date ASC, units ASC

How to group by date

Below I cannot do Group by Date the following figures.
I have tried to put Group By in different lines, but not working.
SELECT SUM(a.NetAmount) AS TotalDonation
FROM (
SELECT
(
CASE WHEN bt.BalanceTransactionCurrencyID = 17
THEN bt.BalanceTransactionNet
ELSE
bt.BalanceTransactionNet * (SELECT TOP 1 ExrateValue FROM Exrate WHERE ExrateDate < bt.BalanceTransactionCreated AND bt.BalanceTransactionCurrencyID = CurrencyID ORDER BY ExrateDate Desc)
END
) AS NetAmount
FROM Charge as ch
JOIN BalanceTransaction as bt ON (ch.BalanceTransactionID = bt.BalanceTransactionID)
WHERE ch.ChargeCreatedDate BETWEEN '3-1-2019' AND '3-31-2019'
) AS a
I wanted to see:
Days Total Amount
March 1 xxxx
March 2 xxxx
March 3 xxx
MySQL does not use TOP. Use LIMIT:
SELECT ChargeCreatedDate, SUM(netamount)
FROM (SELECT ch.ChargeCreatedDate,
(CASE WHEN bt.BalanceTransactionCurrencyID = 17
THEN bt.BalanceTransactionNet
ELSE bt.BalanceTransactionNet * (SELECT e.ExrateValue
FROM Exrate e
WHERE e.ExrateDate < bt.BalanceTransactionCreated AND
e.CurrencyID = bt.BalanceTransactionCurrencyID
ORDER BY ExrateDate Desc
LIMIT 1
)
END) AS NetAmount
FROM Charge ch JOIN
BalanceTransaction bt
ON ch.BalanceTransactionID = bt.BalanceTransactionID
WHERE ch.ChargeCreatedDate BETWEEN '2019-03-01' AND '2019-03-31'
) chtbt
GROUP BY ChargeCreatedDate;
If you happen to be using SQL Server, you can replace the LIMIT 1 with FETCH FIRST 1 ROW ONLY.
The following code will hopefully display what you are looking for
SELECT a.Days AS Days, SUM(cast(a.NetAmount as decimal(16,9))) AS TotalDonation
FROM (
SELECT
(
CASE WHEN bt.BalanceTransactionCurrencyID = 17
THEN bt.BalanceTransactionNet
ELSE
bt.BalanceTransactionNet * (SELECT TOP 1 ExrateValue FROM Exrate WHERE ExrateDate < bt.BalanceTransactionCreated AND bt.BalanceTransactionCurrencyID = CurrencyID ORDER BY ExrateDate Desc)
END
) AS NetAmount,
ch.ChargeCreatedDate as Days
FROM Charge as ch
JOIN BalanceTransaction as bt ON (ch.BalanceTransactionID = bt.BalanceTransactionID)
WHERE ch.ChargeCreatedDate BETWEEN '3-1-2019' AND '3-31-2019'
) AS a GROUP BY a.Days
This should be sufficient. You need to SELECT the desired value in the query in order to get it to show up. Also when using the SUM() function you need to specify what the group value will be.

mysql address outer query from subquery

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;

JIRA : Issue status count for the past x (i.e 30 ) days

With below Query I able to see the count(no) of issues for all issueType in JIRA for a given date .
ie.
SELECT count(*), STEP.STEP_ID
FROM (SELECT STEP_ID, ENTRY_ID
FROM OS_CURRENTSTEP
WHERE OS_CURRENTSTEP.START_DATE < '<your date>'
UNION SELECT STEP_ID, ENTRY_ID
FROM OS_HISTORYSTEP
WHERE OS_HISTORYSTEP.START_DATE < '<your date>'
AND OS_HISTORYSTEP.FINISH_DATE > '<your date>' ) As STEP,
(SELECT changeitem.OLDVALUE AS VAL, changegroup.ISSUEID AS ISSID
FROM changegroup, changeitem
WHERE changeitem.FIELD = 'Workflow'
AND changeitem.GROUPID = changegroup.ID
UNION SELECT jiraissue.WORKFLOW_ID AS VAL, jiraissue.id as ISSID
FROM jiraissue) As VALID,
jiraissue as JI
WHERE STEP.ENTRY_ID = VALID.VAL
AND VALID.ISSID = JI.id
AND JI.project = <proj_id>
Group By STEP.STEP_ID;
the result is
Status Count
open 12
closed 13
..... ....
What I'd like to achieve is something like this actually ..where the total count for status open and closed for each day .
Date COUNT(Open) COUNT(Closed)
12-1-2012 12 1
13-1-2012 14 5
The general strategy would be this:
Select from a table of all the days in a month
LEFT OUTER JOIN your table that gets counts for each day
(left outer join being necessary in case there were no entries for that day, you'd want it to show a zero value).
So I think this is roughly what you need (not complete and date-function syntax is probably wrong for your db, but it will get you closer):
SELECT aDate
, COALESCE(SUM(CASE WHEN IssueStatus = 'whateverMeansOpen' THEN 1 END,0)) OpenCount
, COALESCE(SUM(CASE WHEN IssueStatus = 'whateverMeansClosed' THEN 1 END,0)) ClosedCount
FROM
(
SELECT DATEADD(DAY, I, #START_DATE) aDate
FROM
(
SELECT number AS I FROM [SomeTableWithAtLeast31Rows]
where number between 1 and 31
) Numbers
WHERE DATEADD(DAY, I, #START_DATE) < #END_DATE
) DateTimesInInterval
LEFT OUTER JOIN
(
Put your query here. It needs to output two columns, DateTimeOfIssue and IssueStatus
) yourHugeQuery ON yourHugeQuery.DateTimeOfIssue BETWEEN aDate and DATEADD(DAY, 1, aDate)
GROUP BY aDate
ORDER BY aDate

mysql find date where no row exists for previous day

I need to select how many days since there is a break in my data. It's easier to show:
Table format:
id (autoincrement), user_id (int), start (datetime), end (datetime)
Example data (times left out as only need days):
1, 5, 2011-12-18, 2011-12-18
2, 5, 2011-12-17, 2011-12-17
3, 5, 2011-12-16, 2011-12-16
4, 5, 2011-12-13, 2011-12-13
As you can see there would be a break between 2011-12-13 and 2011-12-16. Now, I need to be able say:
Using the date 2011-12-18, how many days are there until a break:
2011-12-18: Lowest sequential date = 2011-12-16: Total consecutive days: 3
Probably: DATE_DIFF(2011-12-18, 2011-12-16)
So my problem is, how can I select that 2011-12-16 is the lowest sequential date? Remembering that data applies for particular user_id's.
It's kinda like the example here: http://www.artfulsoftware.com/infotree/queries.php#72 but in the reverse.
I'd like this done in SQL only, no php code
Thanks
SELECT qmin.start, qmax.end, DATE_DIFF( qmax.end, qmin.start ) FROM table AS qmin
LEFT JOIN (
SELECT end FROM table AS t1
LEFT JOIN table AS t2 ON
t2.start > t1.end AND
t2.start < DATE_ADD( t1.end, 1 DAY )
WHERE t1.end >= '2011-12-18' AND t2.start IS NULL
ORDER BY end ASC LIMIT 1
) AS qmax
LEFT JOIN table AS t2 ON
t2.end < qmin.start AND
t2.end > DATE_DIFF( qmin.start, 1 DAY )
WHERE qmin.start <= '2011-12-18' AND t2.start IS NULL
ORDER BY end DESC LIMIT 1
This should work - left joins selects one date which can be in sequence, so max can be fineded out if you take the nearest record without sequential record ( t2.anyfield is null ) , same thing we do with minimal date.
If you can calculate days between in script - do it using unions ( eg 1. row - minimal, 2. row maximal )
Check this,
SELECT DATEDIFF((SELECT MAX(`start`) FROM testtbl WHERE `user_id`=1),
(select a.`start` from testtbl as a
left outer join testtbl as b on a.user_id = b.user_id
AND a.`start` = b.`start` + INTERVAL 1 DAY
where a.user_id=1 AND b.`start` is null
ORDER BY a.`start` desc LIMIT 1))
DATEDIFF() show difference of the Two days, if you want to number of consecutive days add one for that result.
If it's not a beauty contents then you may try something like:
select t.start, t2.start, datediff(t2.start, t.start) + 1 as consecutive_days
from tab t
join tab t2 on t2.start = (select min(start) from (
select c1.*, case when c2.id is null then 1 else 0 end as gap
from tab c1
left join tab c2 on c1.start = adddate(c2.start, -1)
) t4 where t4.start <= t.start and t4.start >= (select max(start) from (
select c1.*, case when c2.id is null then 1 else 0 end as gap
from tab c1
left join tab c2 on c1.start = adddate(c2.start, -1)
) t3 where t3.start <= t.start and t3.gap = 1))
where t.start = '2011-12-18'
Result should be:
start start consecutive_days
2011-12-18 2011-12-16 3