Use a sub query result - mysql

I have a table with numbers and dates (1 number each date and dates aren't necessarily at regular intervals).
I would like to get the count of dates when a number isn't in the table.
Where I am :
select *
from
(
select
date from nums
where chiffre=1
order by date desc
limit 2
) as f
I get this :
date
--------------
2014-09-07
--------------
2014-07-26
Basically, I have this query dynamically:
select * from nums where date between "2014-07-26" and "2014-09-07"
And in a second time, browse the whole table (because there I limited to the first 2 rows but I would compare the 2 and 3 and 3 and 4 etc...)
The goal is to get this:
date | actual_number_of_real_dates_between_two_given_dates
2014-09-07 - 2014-07-26 | 20
2014-04-02 - 2014-02-12 | 13
etc...
How can I do this? Thanks.
Edit:
What I have (just an example, dates and "chiffre" are more complex) :
date | chiffre
2014-09-30 | 2
2014-09-29 | 1
2014-09-28 | 2
2014-09-27 | 2
2014-09-26 | 1
2014-09-25 | 2
2014-09-24 | 2
etc...
What I need for the number "1":
actual_number_of_real_dates_between_two_given_dates
1
3
etc...
Edit 2:
My updated query thanks to Gordon Linoff
select count(n.id) as difference
from nums n inner join
(select min(date) as d1, max(date) as d2
from (select date from nums where chiffre=1 order by date desc limit 2) d
) dd
where n.date between dd.d1 and dd.d2
How can I test row 2 with 3? 3 with 4 etc... Not only last 2?
Should I use a loop? Or I can do it without?

Does this do what you want?
select count(distinct n.date) as numDates,
(datediff(dd.d2, dd.d1) + 1) as datesInPeriod,
(datediff(dd.d2, dd.d1) + 1 - count(distinct n.date)) as missingDates
from nums n cross join
(select date('2014-07-26') as d1, date('2014-09-07') as d2) d
where n.date between dd.d1 and dd.d2;
EDIT:
If you just want the last two dates:
select count(distinct n.date) as numDates,
(datediff(dd.d2, dd.d1) + 1) as datesInPeriod,
(datediff(dd.d2, dd.d1) + 1 - count(distinct n.date)) as missingDates
from nums n cross join
(select min(date) as d1, max(date) as d2
from (select date from nums order by date desc limit 2) d
) dd
where n.date between dd.d1 and dd.d2;

Related

Select difference based on record having minimum and maximum date in MySql

Below is my table let's call account
**ID accountID score tracking_date
1 1 3 2014-09-25 00:01:05
2 2 4 2014-09-26 01:05:18
3 1 6 2014-09-27 09:23:05
4 2 9 2014-09-28 20:01:05
5 1 1 2014-09-28 23:21:34
6 3 7 2014-09-21 00:01:00
7 2 1 2014-09-22 01:45:24
8 2 9 2014-09-27 14:01:43
9 3 1 2014-09-24 22:01:27
I want to select record with max date and also the difference of score with the records having tracking_date as minimum for that accountId. So I want output like below
ID accountID score_with_maxdate diff_score_with_mindate max_tracking_date
1 1 1 -2 2014-09-28 23:21:34
2 2 9 8 2014-09-28 20:01:05
3 3 1 -6 2014-09-24 22:01:27
Any help?
Here is one option. We can self-join a subquery which finds both the min and max tracking dates, for each account, twice to your original table. This will bring in all metadata for those max tracking date records, including the scores.
SELECT
t1.accountID,
t2.score AS score_with_maxdate,
t2.score - t3.score AS diff_score_with_mindate,
t1.max_tracking_date
FROM
(
SELECT
accountID,
MAX(tracking_date) AS max_tracking_date,
MIN(tracking_date) AS min_tracking_date
FROM yourTable
GROUP BY accountID
) t1
INNER JOIN yourTable t2
ON t1.accountId = t2.accountID AND t2.tracking_date = t1.max_tracking_date
INNER JOIN yourTable t3
ON t1.accountId = t3.accountID AND t3.tracking_date = t1.min_tracking_date
ORDER BY
t1.accountID;
Demo
This is a somewhat tricky question. I think conditional aggregation is a convenient way to solve the problem:
select min(t.id) as id, t.accountId,
max(case when t.tracking_date = t2.max_td then t.score end) as score_with_maxdate,
max(case when t.tracking_date = t2.max_td then t.score
when t.tracking_date = t2.min_td then - t.score
end) as diff_score_with_mindate,
max(t.tracking_date) as max_tracking_date
from t join
(select t2.accountId, min(t2.tracking_date) as min_td, max(t2.tracking_date) as max_td
from t t2
group by t2.accountId
) t2
on t.accountId = t2.accountId
group by t.accountId;
Another hackish way of getting same results by using aggregate and string fucntion
select t.accountID,
t.score_with_maxdate,
t.score_with_maxdate - t.score_with_mindate score_with_maxdate,
t.max_tracking_date
from(
select accountID,
substring_index(group_concat(score order by tracking_date desc),',', 1) + 0 score_with_maxdate,
substring_index(group_concat(score order by tracking_date asc),',', 1) + 0 score_with_mindate,
max(tracking_date) max_tracking_date
from demo
group by accountID
) t
Demo
But i would suggest you to go with other solutions mentioned by Tim & Gordon

SQL retrieving most recent record (dated) per ID?

SELECT detailsID,`Topic 1 Scores`, MAX(Date) as "Date"
FROM Information.scores
WHERE `Topic 1 Scores` IS NOT NULL
GROUP BY `detailsID`,`Topic 1 Scores`
Is printing;
detailsID, Topic 1 Scores, MAX(Date)
2 0 26/09/2017
2 45 26/09/2017
2 100 26/09/2017
3 30 25/09/2017
3 80 14/10/2017
Rather than actually selecting the most recent date per detailsID which would be:
2 100 26/09/2017
3 80 14/10/2017
I want to retrieve TOPIC 1 SCORES with the most recent score (excluding null) (sorted by date) for each detailsID, (there are only detailsID 2 and 3 here, therefore only two results should return)
Solution 1 attempt
Inner subquery
You can do this:
SELECT t1.detailsID, t1.`Topic 1 Scores`, t1.date
FROM scores as t1
INNER JOIN
(
SELECT detailsID, MAX(date) as "LatestDate"
FROM scores
WHERE `Topic 1 Scores` IS NOT NULL
GROUP BY `detailsID`
) AS t2 ON t1.detailsID = t2.detailsID AND t1.date = t2.LatestDate
Demo
The subquery will give you the most recent date for each detailsID then in the outer query, there is a join with the original table to eliminate all the rows except those with the most recent date.
Update:
There are some rows with the same latest date, thats why you will have multiple rows with the same date and the same detailsID, to solve this you can add another aggregate for the score, so that you have only one row for each details id with the latest date and max score:
SELECT t1.detailsID, t1.`Topic 1 Scores`, t1.date
FROM scores as t1
INNER JOIN
(
SELECT detailsID, MAX(`Topic 1 Scores`) AS MaxScore, MAX(date) as "LatestDate"
FROM scores
WHERE `Topic 1 Scores` IS NOT NULL
GROUP BY `detailsID`
) AS t2 ON t1.detailsID = t2.detailsID
AND t1.date = t2.LatestDate
AND t1.`Topic 1 Scores` = t2.MaxScore
updated demo
Results:
| detailsID | Topic 1 Scores | date |
|-----------|----------------|------------|
| 2 | 100 | 2017-09-26 |
| 3 | 80 | 2017-10-14 |
WITH MYCTE AS
(
SELECT DetailsId, [Topic 1 Score], ROW_NUMBER() OVER ( Partition BY DetailsID ORDER BY DATE DESC) Num
FROM Scores
)
SELECT * FROM MYCTE WHERE num = 1
GO

COUNT DISTINCT + COUNT GROUP BY HAVING (value) + GROUP BY months

I have a table with columns: cid, date
Sample table data: Note: cid contains string values eg: 'otsytb8o7sbs50w9doghwzvfy0vb8f9h' many are duplicated.
cid. date
--------------------------------------------------------
1 2015-10-10 04:57:57
2 2015-10-10 05:03:58
3 2015-10-10 05:24:49
4 2015-10-10 05:28:24
5 2015-10-10 05:28:26
6 2015-10-10 05:28:40
7 2015-10-10 05:30:39
8 2015-10-10 05:33:04
9 2015-10-10 05:35:42
9 2015-10-10 05:36:03
I want to get the following:
Count of Distinct cid as uniqVisits
Count of cid HAVING (count <= 1) as bounced
Grouped by month
I want to get bounce rate per month from Cookie ID's (cid).
So I am looking for: ( COUNT of unique Cookie ID's with a count of <=1 ) for bounced, and ( COUNT DISTINCT cid's ) for total unique visitors, Grouped By month
Desired result:
uniqVisits | bounced | month
-----------|---------|-------
2345 | 325 | 2015-10
-----------|---------|-------
7345 | 734 | 2015-11
-----------|---------|-------
3982 | 823 | 2015-12
-----------|---------|-------
4291 | 639 | 2016-01
I have tried a lot of methods the below is the closest I can get but it gives me error: "Operand should contain 1 column(s)"
SELECT count(*) AS bounced,
( SELECT count( DISTINCT(cid) ) AS uniqVisits,
SUBSTR(DATE(date),1,7) AS month
FROM table ) AS uniqVisits
FROM (
SELECT COUNT(cid) AS bounced,
SUBSTR(DATE(date),1,7) AS month
FROM table
GROUP BY cid
HAVING (count <= 1)
) AS x
GROUP BY month
How can I write this query to give me the desired result I want in the "Desired result:" chart / table illustrated above?
BTW: I also tried the below query but it times out, and then throws a server error: It also does not group the second query into month, obviously because of the "cid having count <=1"
SELECT c1.uniqVisits,
c1.month,
c2.bounced
FROM ( SELECT COUNT(DISTINCT t1.cid) AS `uniqVisits`,
SUBSTR(DATE(t1.date),1,7) AS `month`
FROM table t1
GROUP BY month
) c1
JOIN ( SELECT COUNT(*) AS `bounced`,
SUBSTR(DATE(t2.date),1,7) AS `month`
FROM table t2
GROUP BY month, cid HAVING (count <= 1)
) c2
ON c2.month = c1.month
ORDER BY c1.month
So I have resolved this:
SELECT uniqVisitors, COUNT(*) AS bounced, T1.month
FROM (
SELECT cid,
SUBSTR(DATE(date),1,7) AS month
FROM table
GROUP BY cid
HAVING COUNT(*) <= 1
) T1
LEFT JOIN
( SELECT count( DISTINCT(cid) ) AS uniqVisitors,
SUBSTR(DATE(date),1,7) AS month
FROM table
GROUP By month ) T2
ON T1.month = T2.month
GROUP BY month
Gives me:
uniqVisitors | bounced | month
---------------------------------
7237 6822 2015-10
12597 12136 2015-11
12980 12573 2015-12
12091 11695 2016-01
5396 5134 2016-02

How can I combine the values of a single column in SQL

I have the table in the following format.
BatchID BatchTime
1 10:00:00
2 13:00:00
3 16:00:00
4 19:00:00
And I what I actually need is:
BatchID BatchTime
1 10:00:00 - 13:00:00
2 13:00:00 - 16:00:00
3 16:00:00 - 19:00:00
4 19:00:00 - 10:00:00
Assuming you have consecutive ids you can do the following:
SELECT a.id,a.dt date_a, b.dt date_b FROM tbl a
INNER JOIN tbl b ON b.id=a.id % (SELECT MAX(id) FROM tbl) + 1
ORDER BY a.id
See here: http://sqlfiddle.com/#!3/24791/6
Should, however, the times dt not be ascending with id (which incidentally could also have gaps) then the following will still work:
WITH t AS (SELECT id,dt,ROW_NUMBER() OVER (ORDER BY dt) n FROM tbl)
SELECT a.id,a.dt date_a, b.dt date_b FROM t a
INNER JOIN t b ON b.n=a.n % (SELECT MAX(n) FROM t) + 1
ORDER BY a.n -- order by ascending times in table a
See here: http://sqlfiddle.com/#!3/74ed6/1
The window function ROW_NUMBER() puts the times in an ascending order in the common table expression t. After that two ts are joined in a cyclic manner (using modulus % on the newly generated row number n).
a.n % (SELECT MAX(n) FROM t) + 1 will always calculate the "next" line in the cyclic order with which to join table t with alias b.

Loop or recursive sql query

I have a table with numbers and dates (1 number each date and dates aren't necessarily at regular intervals). I would like to get the count of dates when a number isn't in the table.
What I have (just an example, dates and "chiffres" are more complex) :
date | chiffre
2014-09-30 | 2
2014-09-29 | 1
2014-09-28 | 2
2014-09-27 | 2
2014-09-26 | 1
2014-09-25 | 2
2014-09-24 | 2
etc...
What I need for the number "1":
actual_number_of_real_dates_between_two_given_dates
1
3
My actual query thanks to Gordon Linoff
select count(n.id) as difference
from nums n inner join
(select min(date) as d1, max(date) as d2
from (select date from nums where chiffre=1 order by date desc limit 2) d
) dd
where n.date between dd.d1 and dd.d2
How can I test row 2 with 3? 3 with 4 etc... Not only last 2? Without "limit 2"
Should I use a loop? Or I can do it without?
If you are trying to find the gaps between 1s in the table, you should start with the next "1":
select n.*,
(select date
from nums n2
where n2.chiffre = 1 and n2.date > n.date
order by date
limit 1
) next_date
from nums n
where chiffre = 1;
Then use this as a subquery to get what you want:
select n.*,
datediff(coalesce(next_date, now()), date) as days_between
from (select n.*,
(select date
from nums n2
where n2.chiffre = 1 and n2.date > n.date
order by date
limit 1
) next_date
from nums n
where chiffre = 1
) n;