Looking at other posts was not working due to my lack of ability .
I am trying to extract a Cohort from the date of installation .
information TABLE
u_status
used : created_at , last_login
u_daily_login
SQL
SET
#targetDate = '2020-07-01';
SELECT
#Datecount := TIMESTAMPDIFF(
DAY,
#targetDate,
DATE_FORMAT(NOW(), '%Y-%m-%d')) -1;
SELECT
dl.df,
COUNT(udl.uMasterId)
FROM
(
SELECT
DATE_FORMAT(
DATE_ADD(
#targetDate,
INTERVAL td.generate_series DAY
),
'%Y-%m-%d'
) AS df
FROM
(
SELECT
0 generate_series
FROM DUAL
WHERE
(#num := 1 -2) * 0
UNION ALL
SELECT
#num := #num +1
FROM
`information_schema`.COLUMNS
WHERE
#num <= #Datecount
) AS td
) AS dl
LEFT JOIN(
SELECT udlt.*
FROM
(
SELECT
*
FROM
u_daily_login
WHERE
DATE >= #targetDate
) AS udlt
INNER JOIN(
/*基準日に登録したユニークユーザー*/ SELECT
*
FROM
(
SELECT
DATE_FORMAT(us.`createdAt`, '%Y-%m-%d') AS cdate,
us.name,
uMasterId
FROM
u_status AS us
WHERE
DATE_FORMAT(us.`createdAt`, '%Y-%m-%d') = #targetDate
) AS noise
GROUP BY
noise.name
) AS uus
ON
uus.uMasterId = udlt.uMasterId
) AS udl
ON
dl.df = udl.date
GROUP BY
dl.df
LIMIT 100;
I got the desired result, As it is now, I'm typing targetDate manually.
ex. #targetDate = 2020-07-02 , "targetDate = 2020-07-03 ...etc
How can I efficiently extract daily cohorts?
Essentially, I want to find out how much time is spent on a product.
Each product is identified by the model_id and different people may work on
each product. I want the time difference between when the product is being worked on and when there is more than a 5 minute gap.
example table
CREATE TABLE test (id INT, created_at DATETIME, model_id INT, TIMEDIFF DATETIME, TOTALTIME DATETIME)
SELECT '144111', '2019-03-30 11:14:26','301302','',''
UNION
SELECT '144112', '2019-03-30 11:14:33','301302','',''
UNION
SELECT '144113', '2019-03-30 11:14:33','301302','',''
UNION
SELECT '144114', '2019-03-30 11:14:54','301302','',''
UNION
SELECT '144115', '2019-03-30 11:15:35','301302','',''
UNION
SELECT '144116', '2019-03-30 11:22:21','301302','',''
UNION
SELECT '144117', '2019-03-30 11:23:14','301302','',''
UNION
SELECT '144118', '2019-03-30 11:24:24','301302','',''
UNION
SELECT '144119', '2019-03-30 11:25:35','301302','',''
my attempt
WHILE (SELECT COUNT(model_id) FROM portal3_projectsolar.`qat_` WHERE `timediff` IS NULL) > 0 DO #begining of while loop
#min modelid
SET #modelid = (SELECT MIN(model_id) FROM `portal3_projectsolar`.`qat_` WHERE `Timediff` IS NULL);
#set the times
SET #starttime = (SELECT MIN(created_at) FROM `portal3_projectsolar`.`qat_` a WHERE a.model_id = #modelid AND a.`Timediff` IS NULL ORDER BY a.model_id, a.created_at);
SET #endtime = (SELECT MIN(created_at) FROM `portal3_projectsolar`.`qat_` a WHERE a.model_id = #modelid AND a.created_at > #starttime AND a.`Timediff` IS NULL ORDER BY a.model_id, a.created_at);
SET #Nexttime = (SELECT MIN(created_at) FROM `portal3_projectsolar`.`qat_` a WHERE a.model_id = #modelid AND a.created_at > #endtime AND a.`Timediff` IS NULL ORDER BY a.model_id, a.created_at);
# compare the endtime and the nexttime. if nextime is 5 minutes more than endtime then endtime is endtime
WHILE (SELECT DATE_ADD(#endtime,INTERVAL 30 MINUTE) > #Nextdate) DO
SET #Endtime =(SELECT #Nexttime);
SET #Nexttime = (SELECT MIN(created_at) FROM `portal3_projectsolar`.`qat_` WHERE model_id = #modelid AND created_at > #endtime AND `Timediff` IS NULL ORDER BY model_id, created_at);
END WHILE;
#the time diffrence
SET #timediff = (SELECT TIMESTAMPDIFF(MINUTE, #starttime, #endtime));
SET #startid = (SELECT MIN(id) FROM qat_ WHERE created_at = #starttime);
SET #endid = (SELECT MIN(id) FROM qat_ WHERE created_at = #endtime);
#update the time diff for the id range
UPDATE portal3_projectsolar.`qat_`
SET `timediff` = #timediff
WHERE Created_at = BETWEEN #starttime AND #Endtime;
END WHILE;
The results should show the difference of the start and end in the timediff column and the total time spent for each model_id in the totaltime column
Inside a WHERE inside a subquery inside a FROM inside another subquery inside a SELECT that's joined to another table, I need to access a column from that joined table.
edited to add more complete example:
SELECT
field_one,
field_two,
field_three,
field_one-field_three AS field_five,
field_six
FROM (
SELECT
IFNULL(
(
SELECT
SUM(us.field_seven) AS field_one
FROM
table_one us
WHERE
us.rto_id = rto.relevant_field_one
AND
us.created >= (
SELECT
IF(
selected_date IS NULL,
MIN(created),
selected_date
)
FROM (
SELECT
IF(
latest_date < DATE_SUB(CURDATE(), INTERVAL rtt.relevant_field_two DAY),
CURDATE(),
MAX(prevdate)
) AS selected_date,
created
FROM (
SELECT
created,
#calc_prevdate as prevdate,
DATEDIFF(#calc_prevdate, created) AS diff,
#calc_prevdate := created
FROM (
SELECT
sto.created
FROM
table_one sto
WHERE
sto.rto_id = rto.relevant_field_one
UNION ALL
SELECT
stt.created
FROM
table_two stt
WHERE
stt.rto_id = rto.relevant_field_one
ORDER BY
created DESC
) AS x
CROSS JOIN (
SELECT
#calc_prevdate := NULL
) as vars
) AS z
CROSS JOIN (
SELECT
MAX(created) AS latest_date
FROM(
SELECT
sto.created
FROM
table_one sto
WHERE
sto.rto_id = rto.relevant_field_one
UNION ALL
SELECT
stt.created
FROM
table_two stt
WHERE
stt.rto_id = rto.relevant_field_one
ORDER BY
created DESC
) as z
) AS y
WHERE
diff > rtt.relevant_field_two
) as w
)
GROUP BY us.rto_id
),0
) AS field_one,
IFNULL(
(
SELECT
SUM(tt.field_seven) AS field_three
FROM
table_two tt
WHERE
tt.rto_id = rto.relevant_field_one
AND
tt.created >= (
SELECT
IF(
selected_date IS NULL,
MIN(created),
selected_date
)
FROM (
SELECT
IF(
latest_date < DATE_SUB(CURDATE(), INTERVAL rtt.relevant_field_two DAY),
CURDATE(),
MAX(prevdate)
) AS selected_date,
created
FROM (
SELECT
created,
#calc_prevdate as prevdate,
DATEDIFF(#calc_prevdate, created) AS diff,
#calc_prevdate := created
FROM (
SELECT
sto.created
FROM
table_one sto
WHERE
sto.rto_id = rto.relevant_field_one
UNION ALL
SELECT
stt.created
FROM
table_two stt
WHERE
stt.rto_id = rto.relevant_field_one
ORDER BY
created DESC
) AS x
CROSS JOIN (
SELECT
#calc_prevdate := NULL
) as vars
) AS z
CROSS JOIN (
SELECT
MAX(created) AS latest_date
FROM(
SELECT
sto.created
FROM
table_one sto
WHERE
sto.rto_id = rto.relevant_field_one
UNION ALL
SELECT
stt.created
FROM
table_two stt
WHERE
stt.rto_id = rto.relevant_field_one
ORDER BY
created DESC
) as z
) AS y
WHERE
diff > rtt.relevant_field_two
) as w
)
GROUP BY tt.rto_id
), 0
) AS field_three,
IFNULL(
(
SELECT
COUNT(*) AS field_two
FROM
table_two tt
WHERE
tt.rto_id = rto.relevant_field_one
GROUP BY tt.rto_id
), 0
) AS field_two,
IFNULL(
(
SELECT
GREATEST(
IFNULL(MAX(us.created), 0), IFNULL(MAX(tt.created), 0)
) AS field_six
FROM
table_one us
LEFT JOIN
table_two tt ON us.rto_id = tt.rto_id
WHERE
us.rto_id = rto.relevant_field_one
GROUP BY us.rto_id
), 0
) AS field_six
FROM
relevant_table_one rto
LEFT JOIN
relevant_table_two rtt ON rto.rtt_id = rtt.id
WHERE
rto.rtt_id = ?
GROUP BY rto.relevant_field_one
) v
ORDER BY id ASC;
given that query, I need to access relevant_table_one.relevant_field_one and relevant_table_two.relevant_field_two from inside the subqueries, but the restrictions on subqueries dictates that you cant access a parents table in a subquery inside a FROM
I managed to solve this (so far I think) by adding #rfo := relevant_field_one and #rft := relevant_field_two up in the select where they were accessable and then referring to the created variables instead of the columns down in the nested query where relevant.
It's possible I'm just getting false positives but so far the solution appears to be working.
I'm trying to create a query using SELECT CASE that would return the accumulative results.
Here is my query, it works but doesnt return the correct result.
SELECT total, count(*) as count FROM
(
SELECT case
WHEN ( X ) < 1 THEN '1 km'
WHEN ( X ) < 3 THEN '3 km'
WHEN ( X ) < 5 THEN '5 km'
WHEN ( X ) < 10 THEN '10 km'
WHEN ( X ) < 15 THEN '15 km'
WHEN ( X ) < 25 THEN '25 km'
WHEN ( X ) < 50 THEN '50 km'
WHEN ( X ) < 100 THEN '100 km'
WHEN ( X ) > 0 THEN '-1'
else '-2'
end AS `total`
FROM `store` AS d WHERE d.pending!='1'
) AS someRandomAliasHere
GROUP BY `total`
X is a formula i'm using to calculate radius from a lat and lang. total is NOT a column in my database table, just a result to calculations of X
The query above gives me this..
1 km (4)
3 km (19)
5 km (103)
25 km (540)
50 km (61)
....
4,19,103,540,62 are the total matches found.
The total count for 3 should be 19+4=23.
5 should be 103+19+4=122 etc. And WHEN ( X ) > 0 THEN '-1' should show the total count. of matches
I tried using BETWEEN 0 AND 1, BETWEEN 0 AND 3 etc but it still didn't give me the correct results
Any ideas?
Another approach is to calculate the results independently then union them:
SELECT 1 AS total, COUNT(*) AS cnt FROM `store` WHERE store.pending != 1 AND ( X ) < 1
UNION ALL
SELECT 3 AS total, COUNT(*) AS cnt FROM `store` WHERE store.pending != 1 AND ( X ) < 3
UNION ALL
SELECT 5 AS total, COUNT(*) AS cnt FROM `store` WHERE store.pending != 1 AND ( X ) < 5
UNION ALL
/** ... **/
SELECT 100 AS total, COUNT(*) AS cnt FROM `store` WHERE store.pending != 1 AND ( X ) < 100
In addition to the accumulation, you also want a total value at the end with -1. This is a bit of a pain, but it can be accomplished.
The simplest way to do cumulative sums in MySQL is using variables. The basic idea is this:
SELECT total, cnt, (#cnt := #cnt + cnt) as count
FROM (SELECT (case WHEN ( X ) < 1 THEN '1'
WHEN ( X ) < 3 THEN '3'
WHEN ( X ) < 5 THEN '5'
WHEN ( X ) < 10 THEN '10'
WHEN ( X ) < 15 THEN '15'
WHEN ( X ) < 25 THEN '25'
WHEN ( X ) < 50 THEN '50'
WHEN ( X ) < 100 THEN '100'
WHEN ( X ) > 0 THEN '-1'
else '-2'
end) AS total, COUNT(*) as cnt
FROM store s
WHERE s.pending <> '1'
GROUP BY total
) t CROSS JOIN
(SELECT #cnt := 0) vars
ORDER BY total;
The issue with this is that you will not get an overall total of the non-negative values. Let me assume that you have no negative values. This requires adding another row into the total line:
SELECT total, cnt, (#cnt := #cnt + cnt) as count
FROM (SELECT (case WHEN ( X ) < 1 THEN '1'
WHEN ( X ) < 3 THEN '3'
WHEN ( X ) < 5 THEN '5'
WHEN ( X ) < 10 THEN '10'
WHEN ( X ) < 15 THEN '15'
WHEN ( X ) < 25 THEN '25'
WHEN ( X ) < 50 THEN '50'
WHEN ( X ) < 100 THEN '100'
WHEN ( X ) > 0 THEN '-1'
else '-2'
end) AS total, COUNT(*) as cnt
FROM store s
WHERE s.pending <> '1'
GROUP BY `total`
UNION ALL
SELECT -1, 0
) t CROSS JOIN
(SELECT #cnt := 0) vars
ORDER BY (total >= 0) desc, total;
I've changed the order by as well. Note that the value -2 is probably meaningless, because X < 1 and X > 0 cover all possible values of X (except for NULL). If you actually have values 100 or greater, there are some small changes to refine the query. You do not describe what to do with those values, so clarification on the question would be helpful.
Not sure if this works since I don't have a database to test this on. Also not exactly in the format you want.
select sum(if(X<1,1,0)) as C1,
sum(if(X<3,1,0)) as C3,
sum(if(X<5,1,0)) as C5,
sum(if(X<10,1,0)) as C10,
sum(if(X<15,1,0)) as C15,
sum(if(X<25,1,0)) as C25,
sum(if(X<50,1,0)) as C50,
sum(if(X<100,1,0)) as C100,
sum(if(X>=100,1,0)) as C100P
from store
where store.pending != '1'
Unfortunatelly MySQL do not have analytical functions and windowed functions, but in this case, you can achieve your goal using a variable and a nested subquery:
SELECT
total,
cnt,
#rollupCount:=#rollupCount+cnt AS rollupCount
FROM
(
SELECT
total,
count(*) AS cnt
FROM
(
SELECT
CASE
WHEN ( X ) < 1 THEN '1'
WHEN ( X ) < 3 THEN '3'
WHEN ( X ) < 5 THEN '5'
WHEN ( X ) < 10 THEN '10'
WHEN ( X ) < 15 THEN '15'
WHEN ( X ) < 25 THEN '25'
WHEN ( X ) < 50 THEN '50'
WHEN ( X ) < 100 THEN '100'
WHEN ( X ) > 0 THEN '-1'
ELSE '-2'
END AS `total`
FROM
`store` AS d
WHERE
d.pending != '1'
) AS someRandomAliasHere
GROUP BY
`total`
) AS anotherRandomAliasHere
, (SELECT #rollupCount:=0) AS RC
ORDER BY
total ASC
This is the same as when you want to calculate the row number for each record:
SELECT
#rowNumber:=#rowNumber+1 AS rowNumber,
sourceColumns
FROM
sourceTable, (SELECT #rowNumber:=0) AS t
ORDER BY
orderColumn;
A column to give cumulative totals from an existing query can be created relatively simply:
SELECT X,
total,
(SELECT SUM(total)
FROM (<<<your_current_query>>>) ycq2
WHERE ycq2.X <= ycq1.X) `cumulative_total`
FROM (<<<your_current_query>>>) ycq1
Of course this will expand quite a lot when pasting your current query in the two marked places.
See SQL fiddle demo.
try this:
/sql server version/
DECLARE #GROUPS TABLE (TOTAL INT)
INSERT INTO #GROUPS
VALUES (1),
(3),
(5),
(10),
(15),
(25),
(50),
(100),
(-1)
SELECT a.TOTAL, z.[COUNT] FROM #GROUPS a
CROSS APPLY
(SELECT COUNT(*) as [COUNT] FROM store x WHERE CASE WHEN a.TOTAL = -1 THEN -x.X ELSE x.X END < REPLACE(a.TOTAL,-1,0)
AND pending != 1) z
/mysql version/
CREATE TEMPORARY TABLE GROUPS TABLE (TOTAL INT)
INSERT INTO GROUPS
VALUES (1),
(3),
(5),
(10),
(15),
(25),
(50),
(100),
(-1)
SELECT a.TOTAL, z.[COUNT] FROM GROUPS a
CROSS APPLY
(SELECT COUNT(*) as [COUNT] FROM store x WHERE CASE WHEN a.TOTAL = -1 THEN -x.X ELSE x.X END < REPLACE(a.TOTAL,-1,0)
AND pending != 1) z
try this one :
1.) value after "THEN" must be numeric
2.) make temporary table with running id (example for SQL SERVER)
SELECT identity(int, 1, 1) as id,
case
WHEN ( X ) < 1 THEN 1
WHEN ( X ) < 3 THEN 3
WHEN ( X ) < 5 THEN 5
WHEN ( X ) < 10 THEN 10
WHEN ( X ) < 15 THEN 15
WHEN ( X ) < 25 THEN 25
WHEN ( X ) < 50 THEN 50
WHEN ( X ) < 100 THEN 100
WHEN ( X ) > 0 THEN -1
else '-2' end AS total
Into storeID
FROM store AS d
WHERE d.pending!='1'
Order BY total
3.) join table with same table, with criteria
Select a.*, sum(b.total) as NewTotal
From storeID a
Left Join storeID b
On b.id <= a.id
Group By a.id, a.total
4.) i think, "NewTotal" is what you are looking for
Your question is a bit hard to understand. Is this what you want?
CREATE TABLE Totals (X INT, SUM INT);
INSERT INTO Totals VALUES
(1, 4),
(3, 19),
(5, 103),
(25, 540),
(50, 61)
SELECT first.X
, Sum(second.SUM)
FROM Totals first
JOIN Totals second
ON first.x >= second.x
GROUP BY first.X
UNION
SELECT 0, SUM(sum) * 2
FROM Totals
http://sqlfiddle.com/#!3/65665/12
I suppose that you X function returns a floating point number. If I understand your logic correctly, you want to group together values where X is >=0 and <1, where X >=0 and <3, >=0 and <5 and so on, and you want to return -1 when the value is >=0, and -2 when the value is a negative <0 number.
I would use an intervals table, defined like this:
CREATE TABLE intervals (
i_begin INT,
i_end INT,
i_value INT
);
INSERT INTO intervals VALUES
(0, 1, 1),
(0, 3, 3),
(0, 5, 5),
(0, 10, 10),
(0, 15, 15),
(0, 25, 25),
(0, 50, 50),
(0, 100, 100),
(0, null, -1),
(null, 0, -2);
or you can play with values in this table to make it suite your needs.
then you can just use an INNER JOIN and a GROUP BY query:
SELECT
i_value, COUNT(*)
FROM
store INNER JOIN intervals
ON ((i_begin IS NULL OR X>=i_begin) AND (i_end IS NULL OR X<i_end))
WHERE
store.pending<>1
GROUP BY
i_value
Please see an example here.
I have a query that I have simplified and written below.
How do I display the time difference of 2 fields that were calculated as 2 separate inline select statements?
SELECT x.name ,
( SELECT data.ts
FROM data
WHERE prim_key = x.prim_key and roll_no ='1'
) **starttime** ,
( SELECT data.ts
FROM woman_data
WHERE prim_key = x.prim_key and roll_no ='10'
) **endtime**
, **TIME_TO_SEC( TIMEDIFF( endtime , starttime)** as timediff // This line does not work.It cannot recognize endtime ans starttime
FROM data x
INNER JOIN y
ON x.prim_key = y.prim_key
ORDER BY x.prim_key
try this:
starttime and endtime are derived columns, you cannot use it in the same select statement..
You have to create a derived table then use these columns the a query outside
select name,starttime,endtime,TIME_TO_SEC( TIMEDIFF( endtime , starttime) as timediff
from(
SELECT x.name ,
( SELECT data.ts
FROM data
WHERE prim_key = x.prim_key and roll_no ='1'
) starttime ,
( SELECT data.ts
FROM woman_data
WHERE prim_key = x.prim_key and roll_no ='10'
) endtime
FROM data x
INNER JOIN y
ON x.prim_key = y.prim_key)a
ORDER BY x.prim_key
The easiest way to change a query to have an "outer-level":
SELECT
name,
starttime,
endtime,
TIME_TO_SEC( TIMEDIFF( endtime , starttime)) as timediff
FROM(
SELECT
x.prim_key,
x.name ,
( SELECT data.ts
FROM data
WHERE prim_key = x.prim_key and roll_no ='1'
) starttime ,
( SELECT data.ts
FROM woman_data
WHERE prim_key = x.prim_key and roll_no ='10'
) endtime
FROM data x
INNER JOIN y
ON x.prim_key = y.prim_key
) n
ORDER BY n.prim_key