How to transform a MSSQL CTE query to MySQL 5.7? - mysql

I have one SQL queries
with temp as
(
select min(ms_date) as start, max(ms_date) as [end], count(sessionid) 'visitor_count',category,convert(varchar, ms_date , 106) 'ms_date'
from temp_tbltrack where category =#id
group by category,convert(varchar, ms_date , 106)
)
select category,ms_date,CASE WHEN datediff(ss,temp.start,temp.[end]) <>0 THEN datediff(ss,temp.start,temp.[end]) ELSE 45 END 'Timespan',visitor_count from temp
order by convert(datetime,ms_date)
I converted into Mysql
select temp from
(
select min(ms_date) as start, max(ms_date) as `end`, count(sessionid) 'visitor_count',category,date_format (ms_date , 106) 'ms_date'
from temp_tbltrack where category =p_id
group by category,date_format (ms_date , 106)
)
select category,ms_date,CASE WHEN timestampdiff(ss,temp.start,temp.[end]) <>0 THEN timestampdiff(ss,temp.start,temp.[end]) ELSE 45 END 'Timespan',visitor_count from temp
order by convert(ms_date, datetime);
How I convert CTE in Mysql 5.7 version

I don't think a subquery is needed:
select category,
format(ms_date, '%d %b %Y') as ms_date,
(case when max(ms_date) = min(ms_date)
then 45
else timestampdiff(second, min(ms_date), max(ms_date))
end) as timestamp
count(sessionid) as `visitor_count`,
from temp_tbltrack
where category = #id
group by category, format(ms_date, '%d %b %Y')
order by min(ms_date);

you can use subqueries since you can't use cte on your mysql version.
select t1.category
, t1.ms_date
, case when datediff(ss, temp.start, temp.[end]) <> 0
then datediff(ss,temp.start,temp.[end]) else 45 end 'Timespan'
, t1.visitor_count
from
(select min(ms_date) as start, max(ms_date) as [end], count(sessionid) 'visitor_count', category, cast(ms_date as date) 'ms_date'
from temp_tbltrack where category =#id
group by category, cast(ms_date as date)) t1
order by cast(t1.ms_date as datetime)

Related

How to extract Cohort analysis in SQL ? or MySQL?

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?

why is time differences using alias not working?

SELECT
t.imei,
t.date,
t.time startTime,
t.ignition,
t.tripStartStop,
(
SELECT
min(time)
from
gps_data
where
time > t.time
and date >= t.date
and imei = '358480088853405'
and tripStartStop = 0
) ' stopTime',
SUBTIME('startTime', 'stopTime') AS diff
from
gps_data t
where
imei = '358480088853405'
and date >= '2020-03-08'
and date <= '2020-03-09'
and tripStartStop = 1
the above query returns startTime and stopTime as alias values but i can't get the difference of these two times
used both SUBTIME and TIMEDIFF
You cannot use aliases like that. The query:
SUBTIME('startTime','stopTime')
treats the startTime and stopTime as strings, hence the 00:00:00.
What you can do is following:
select q.imei, q.date, q.startTime, q.ignition,
q.tripStartStop, q.stopTime, subtime(q.startTime, q.stopTime)
from (
SELECT t.imei
, t.date
, t.time startTime
, t.ignition
, t.tripStartStop
, ( SELECT min(time) from gps_data where time>t.time and date>=t.date and imei='358480088853405' and tripStartStop=0 ) 'stopTime'
from gps_data t
where
imei='358480088853405'
and date between '2020-03-08' and '2020-03-09'
and tripStartStop=1
) as q
You need to select 'starTime' and 'stopTime' using select statement within the Substring. That would solve your problem.
SUBTIME(SELECT(startTime),SELECT(stopTime))
SELECT t.imei
, t.date
, t.time startTime
, t.ignition
, t.tripStartStop
, ( SELECT min(time) from gps_data where time>t.time and date>=t.date and imei='358480088853405' and tripStartStop=0 ) ' stopTime'
, SUBTIME(SELECT(startTime),SELECT(stopTime)) diff
from gps_data t
where imei='358480088853405'
and date>='2020-03-08'
and date<='2020-03-09'
and tripStartStop=1````

MySql Start and End price (Min,Max) with Inner Joins

I have a table of prices, 2 types. metal 1 and metal 2.
I have succeeded in getting the max, min price for each metal groups by day.
How can i also select the start (first) and end (last) of every day too?
I am nearly there, but struggling on getting these two final prices...
My SQL fiddle with example data:
http://sqlfiddle.com/#!9/ca4867/1
My query so far:
select
highp.metal_price_datetime_IST AS high_price_metal_price_datetime_IST
, highp.metal_price as highest_price
, lowp.report_term
, lowp.metal_id
, lowp.metal_price as lowest_price
, lowp.metal_price_datetime_IST AS low_price_metal_price_datetime_IST
from (select #report_term:=concat(day(metal_price_datetime_IST), ' ', monthname(metal_price_datetime_IST), ' ', year(metal_price_datetime_IST)) as report_term
, metal_price_datetime_IST
, metal_price
, metal_id
, case when #report_term=#old_report_term then #rn1:=#rn1+1 else #rn1:=1 end as rn
, #old_report_term:=#report_term
from metal_prices
cross join (select #rn1:=0, #old_report_term:='') inituservar1
where metal_price_datetime_IST BETWEEN '2018-02-01' AND LAST_DAY('2018-02-01')
order by metal_id, report_term, metal_price asc) lowp
inner join (select #report_term2:=concat(day(metal_price_datetime_IST), ' ', monthname(metal_price_datetime_IST), ' ', year(metal_price_datetime_IST)) as report_term
, metal_price_datetime_IST
, metal_price
, metal_id
, case when #report_term2=#old_report_term2 then #rn2:=#rn2+1 else #rn2:=1 end as rn
, #old_report_term2:=#report_term2
from metal_prices
cross join (select #rn2:=0, #old_report_term2:='') inituservar1
where metal_price_datetime_IST BETWEEN '2018-02-01' AND LAST_DAY('2018-02-01')
order by metal_id, report_term, metal_price desc) highp
on lowp.rn=highp.rn
and lowp.metal_id = highp.metal_id
and lowp.report_term = highp.report_term
and lowp.rn = 1
and (lowp.metal_id = 1 or lowp.metal_id = 2)
order by lowp.metal_price_datetime_IST DESC
The query you have in your fiddle seems too complex for what needs to be done. I have refactored and rewritten the query. Basically, the query is split in two parts. First one maxminprice determines the max and min price for each day for each metal. Fairly straight forward. The second part firstlastprice is a bit more complex. It finds out the max and min time stamps for each metal for each day. Then joins back to the main table to get the values for those time stamps. The case statement there is to merge the results for max and min (first and last) time so we don't have to do the query twice.
SELECT maxminprice.metal_id,
maxminprice.metal_price_datetime,
maxminprice.max_price,
maxminprice.min_price,
firstlastprice.first_price,
firstlastprice.last_price
FROM (SELECT metal_id,
DATE(metal_price_datetime) metal_price_datetime,
MAX(metal_price) max_price,
MIN(metal_price) min_price
FROM metal_prices
GROUP BY metal_id,
DATE(metal_price_datetime)
ORDER BY metal_id,
DATE(metal_price_datetime)) maxminprice
INNER JOIN (SELECT mp.metal_id,
day_range.metal_price_datetimefl,
SUM(CASE
WHEN TIME(mp.metal_price_datetime) = first_time
THEN
mp.metal_price
ELSE NULL
END) first_price,
SUM(CASE
WHEN TIME(mp.metal_price_datetime) = last_time
THEN
mp.metal_price
ELSE NULL
END) last_price
FROM metal_prices mp
INNER JOIN (SELECT metal_id,
DATE(metal_price_datetime)
metal_price_datetimefl,
MAX(TIME(metal_price_datetime))
last_time,
MIN(TIME(metal_price_datetime))
first_time
FROM metal_prices
GROUP BY metal_id,
DATE(metal_price_datetime))
day_range
ON mp.metal_id = day_range.metal_id
AND DATE(mp.metal_price_datetime) =
day_range.metal_price_datetimefl
AND TIME(mp.metal_price_datetime) IN
( last_time, first_time )
GROUP BY mp.metal_id,
day_range.metal_price_datetimefl) firstlastprice
ON maxminprice.metal_id = firstlastprice.metal_id
AND maxminprice.metal_price_datetime =
firstlastprice.metal_price_datetimefl

Getting the first and last row?

i have another query to select return min, max, start and end price.
It is for a specific month and works perfect for metal_id = 1 but when changed to 2, it returns no data.
please see:
The query below does its job to select the min, max, start and last price per day in a given month.
I would like to select the same but for the whole month, as in show the overall performance for the given month instead of on a daily basis.
Fiddle:
http://sqlfiddle.com/#!9/bee86/1
I just need the last 2 prices, first and last price on the months selected...
select
highp.metal_price_datetime_IST AS high_price_metal_price_datetime_IST
, highp.metal_price as highest_price
, lowp.report_term
, lowp.metal_price as lowest_price
, lowp.metal_price_datetime_IST AS low_price_metal_price_datetime_IST
from (select #report_term:=concat(monthname(metal_price_datetime_IST), ' ', year(metal_price_datetime_IST)) as report_term
, metal_price_datetime_IST
, metal_price
, metal_id
, case when #report_term=#old_report_term then #rn1:=#rn1+1 else #rn1:=1 end as rn
, #old_report_term:=#report_term
from metal_prices
cross join (select #rn1:=0, #old_report_term:='') inituservar1
where datediff(now(), metal_price_datetime_IST) between 0 and 180
and metal_id = 1
order by metal_id, report_term, metal_price asc) lowp
inner join (select #report_term2:=concat(monthname(metal_price_datetime_IST), ' ', year(metal_price_datetime_IST)) as report_term
, metal_price_datetime_IST
, metal_price
, metal_id
, case when #report_term2=#old_report_term2 then #rn2:=#rn2+1 else #rn2:=1 end as rn
, #old_report_term2:=#report_term2
from metal_prices
cross join (select #rn2:=0, #old_report_term2:='') inituservar1
where datediff(now(), metal_price_datetime_IST) between 0 and 180
and metal_id = 1
order by metal_id, report_term, metal_price desc) highp
on lowp.rn=highp.rn
and lowp.metal_id = highp.metal_id
and lowp.report_term = highp.report_term
and lowp.rn = 1
order by lowp.metal_price_datetime_IST 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