Joining two select queries on a results field - php

I'm trying to join a query results on a field, 'min' - which is the hour:min of the event. I have two different select queries in one and I'm trying UNION (which may not be right, just trying different things, I find MySQL documentation very difficult to read).
So I want
H:M and then the result of addCount and projectsNum - so for each hour/min I have the stats.
Where am I going wrong?
(
SELECT
DATE_FORMAT(`when`, '%H:%i') as `min`,
COUNT(`ipAddress`) AS `addCount`
FROM `metric` m
WHERE `when` BETWEEN DATE_SUB(NOW(), INTERVAL 3 HOUR) AND NOW()
GROUP BY DAY(`when`), HOUR(`when`), MINUTE(`when`)
)
UNION
(
SELECT
DATE_FORMAT(v.`created`, '%H:%i') as `min`,
COUNT(v.`projID`) as `projectsNum`
FROM `projects` v
WHERE v.`created` BETWEEN DATE_SUB(NOW(), INTERVAL 3 HOUR) AND NOW()
GROUP BY DAY(v.`created`), HOUR(v.`created`), MINUTE(v.`created`)
)

UNION just appends a set of results to another set of results.
You need to use your second query as a sub-query:
SELECT
DATE_FORMAT(`when`, '%H:%i') as `min`,
COUNT(`ipAddress`) AS `addCount`,
projects_subquery.`projectsNum`
FROM `metric` m
JOIN (
SELECT
DATE_FORMAT(v.`created`, '%H:%i') as `min`,
COUNT(v.`projID`) as `projectsNum`
FROM `projects` v
WHERE v.`created` BETWEEN DATE_SUB(NOW(), INTERVAL 3 HOUR) AND NOW()
GROUP BY DAY(v.`created`), HOUR(v.`created`), MINUTE(v.`created`)
) AS projects_subquery ON projects_subquery.`min` = m.`min`
WHERE `when` BETWEEN DATE_SUB(NOW(), INTERVAL 3 HOUR) AND NOW()
GROUP BY DAY(`when`), HOUR(`when`), MINUTE(`when`)
This query probably performs terribly. I just brute-force copy-pasted from your original query to make it syntactically correct, but there must be a way to optimize it.

Related

Min value from Database in MySQL

Am trying to find the min value from past 30 days, in my table there is one entry for every day, am using this query
SELECT MIN(low), date, low
FROM historical_data
WHERE name = 'bitcoin'
ORDER BY STR_TO_DATE(date,'%d-%m-%Y') DESC
LIMIT 7
But this value not returing the correct value. The structure of my table is
Table structure
And table data which is store is like this
Table data style
Now what i need is to get the minimum low value. But my query not working it give me wrong value which even did not exist in table as well.
Updates:
Here is my updated Table Structure.
enter image description here
And here is my data in this table which look like this
enter image description here
Now if you look at the data, i want to check the name of token omisego and fatch the low value from past 7 days which will be from 2017-12-25 to 2017-12-19
and in this cast the low value is 9.67, but my current query and the query suggested by my some member did not brings the right answer.
Update 2:
http://rextester.com/TDBSV28042
Here it is, basically i have more then 1400 coins and token historical data, which means that there will me more then 1400 entries for same date like 2017-12-25 but having different name, total i have more then 650000 records. so every date have many entries with different names.
To get the lowest row per group you could use following
SELECT a.*
FROM historical_data a
LEFT JOIN historical_data b ON a.name = b.name
AND a.low > b.low
WHERE b.name IS NULL
AND DATE(a.date) >= '2017-12-19' AND DATE(a.date) <= '2017-12-25'
AND a.name = 'omisego'
or
SELECT a.*
FROM historical_data a
JOIN (
SELECT name,MIN(low) low
FROM historical_data
GROUP BY name
) b USING(name,low)
WHERE DATE(a.date) >= '2017-12-19' AND DATE(a.date) <= '2017-12-25'
AND a.name = 'omisego'
DEMO
For last 30 day of 7 days or n days you could write above query as
SELECT a.*, DATE(a.`date`)
FROM historical_data2 a
LEFT JOIN historical_data2 b ON a.name = b.name
AND DATE(b.`date`) >= CURRENT_DATE() - INTERVAL 30 DAY
AND DATE(b.`date`) <= CURRENT_DATE()
AND a.low > b.low
WHERE b.name IS NULL
AND a.name = 'omisego'
AND DATE(a.`date`) >= CURRENT_DATE() - INTERVAL 30 DAY
AND DATE(a.`date`) <= CURRENT_DATE()
;
DEMO
But note it may return more than one records where low value is same, to choose 1 row among these you have specify another criteria to on different attribute
Consider grouping the same and running the clauses
SELECT name, date, MIN(low)
FROM historical_data
GROUP BY name
HAVING name = 'bitcoin'
AND STR_TO_DATE(date, '%M %d,%Y') > DATE_SUB(NOW(), INTERVAL 30 DAY);
Given the structure, the above query should get you your results.
// Try this code ..
SELECT MIN(`date`) AS date1,low
FROM historical_data
WHERE `date` BETWEEN now() - interval 1 month
AND now() ORDER by low ASC;

How to fill empty value when no record in that day using MySQL group by

SELECT `Date`, SUM(Clicks) AS Clicks, DAY(LAST_DAY(NOW())) AS Monthdays
FROM myTbl
WHERE ( DATE BETWEEN DATE_FORMAT(NOW(), '%Y-%m-01') AND NOW() )
AND MoverID = 123 GROUP BY `Date` ASC
I don't want use PROCEDURE like this: http://stackoverflow.com/questions/7252460/mysql-group-by-and-fill-empty-rows
I don't want to create a whole day containing table like this: http://stackoverflow.com/questions/5988179/mysql-group-by-date-how-to-return-results-when-no-rows
I can use SELECT ##global.time_zone, ##session.time_zone; in PHP and after the MySQL query result is out, I make PHP to the same timezone as MySQL, and fill the date by PHP. But is it a way I can just do it in MySQL way?
You can use a trick to generate virtual table having all the dates you need with another table (replace aux with any table in your DB with 31 recored at least):
SELECT CONVERT(#d := DATE_ADD(#d, INTERVAL 1 DAY), DATE) AS `d`
FROM
`aux`,
(SELECT #d := DATE_SUB(CONVERT(DATE_FORMAT(NOW(), '%Y-%m-01'), DATETIME), INTERVAL 1 DAY)) `x`
WHERE
#d < DATE_SUB(NOW(), INTERVAL 1 DAY)
LIMIT
31
And then join you table on it:
SELECT
`aux`.`d` as `Date`,
SUM(IFNULL(`Clicks`, 0))AS `Clicks`,
DAY(LAST_DAY(NOW())) AS `Monthdays`
FROM (
SELECT CONVERT(#d := DATE_ADD(#d, INTERVAL 1 DAY), DATE) AS `d`
FROM
`aux`,
(SELECT #d := DATE_SUB(CONVERT(DATE_FORMAT(NOW(), '%Y-%m-01'), DATETIME), INTERVAL 1 DAY)) `x`
WHERE
#d < DATE_SUB(NOW(), INTERVAL 1 DAY)
LIMIT
31
) aux
LEFT JOIN
myTbl
ON `Date` = `aux`.`d`
GROUP BY `aux`.`d`

Select count from a table with a Where on another table

I have two tables
oc2_visits (fields: id_ad)
oc2_ads (fields: published)
I need to count the visits by grouping the id_ad, and that works, but I need also that the first 9 results have been published not more that 25 days ago.
This is the query I have at the moment:
SELECT count(v.id_ad) AS visits,
v.id_ad,
a.published
FROM oc2_visits AS v,
oc2_ads AS a
WHERE DATE(a.published) >= DATE_SUB(NOW(), INTERVAL 25 DAY)
GROUP BY v.id_ad
ORDER BY visits DESC LIMIT 0,9
but when I try to enter the query in phpmyadmin, it crashes.
What am I doing wrong?
I think you forgot to parse DATE_SUB(NOW(), INTERVAL 25 DAY) into DATE while comparing with a DATE. Hope it'll work.
SELECT count(v.id_ad) AS visits,
v.id_ad,
a.published
FROM oc2_visits AS v,
oc2_ads AS a
WHERE DATE(a.published) >= DATE(DATE_SUB(NOW(), INTERVAL 25 DAY))
GROUP BY v.id_ad
ORDER BY visits DESC LIMIT 0,9
Presumably the root of your problem is the cartesian product between two tables. Simple rule: Never use comma in the from clause. Always use explicit join syntax.
I imagine the query you want looks something like this:
SELECT count(v.id_ad) AS visits, v.id_ad, a.published
FROM oc2_visits v join
oc2_ads a
ON v.id_ad = a.id_ad
WHERE DATE(a.published) >= DATE_SUB(NOW(), INTERVAL 25 DAY)
GROUP BY v.id_ad
ORDER BY visits DESC
LIMIT 0, 9;

How to get sum for different time period in one query

query 1:
SELECT SUM(duration) FROM table_name WHERE timestart >= past24hours
query 2:
SELECT SUM(duration) FROM table_name WHERE timestart >= past7days
Hi all, i want to combined above two query and get sum in query.
Any way to do this?
Currently i have 2 more query in addition to above for past 30 days and 365 days.
Anyone please help.
You can use union
like
SELECT SUM(duration) FROM table_name WHERE timestart >= past24hours
UNION
SELECT SUM(duration) FROM table_name WHERE timestart >= past7days
SELECT SUM(duration), 1 FROM table_name WHERE timestart >= '$date' - INTERVAL 1 DAY
UNION
SELECT SUM(duration), 2 FROM table_name WHERE timestart BETWEEN '$date' - INTERVAL 7 DAY AND '$date' - INTERVAL 1 DAY
this way you wont get rows with timestart in last 24 hours twice
One way is to get all sums with different alias is as
select
t.sum1,t.sum2
from(
select
sum(case when timestart >= past24hours then duration END) as sum1,
sum(case when timestart >= past7days then duration END) as sum2
from table_name
)t
You can add any number of sums within the query and give an alias name and add them in the select list so that they could be parsed later with your server side script.
With UNION it will return the same column/alias. When you have same sum value in UNION it will get only one and to get rid of it you can use UNION ALL

MySQL Query Problem with INTERVAL, need 0 if no data provided

i have the following statement:
SELECT
count(rs.rsc_id) as counter
FROM shots as rs
where rsc_rs_id = 345354
AND YEAR(rs.timestamp) = YEAR(DATE_SUB(CURDATE(), INTERVAL 6 MONTH))
GROUP BY DATE_FORMAT(rs.timestamp,'%Y%m')
rs.timestamp is a unix timestamp
Output would be like for each row / month a numeric like '28'
It Works fine, but if i have inconsistent data, like only for the past three month (not for all six month), i get no return from my Database. I would like to have every time there is not data for this month, 0 returned...
any suggestion?
i thought about some case statements, but this seems not so good...
thanks!!
For only 6 months, a date table seems unnecessary, although this looks complicated (it really isn't!)
SELECT DATE_FORMAT(N.PivotDate,'%Y%m'), count(rs.rsc_id) as counter
FROM (
select ADDDATE(CURDATE(), INTERVAL N MONTH) PivotDate
FROM (
select 0 N union all
select 1 union all
select 2 union all
select 3 union all
select 4 union all
select 5 union all
select 6) N) N
LEFT JOIN shots as rs
ON rsc_rs_id = 345354
AND DATE_FORMAT(N.PivotDate,'%Y%m')=DATE_FORMAT(FROM_UNIXTIME(rs.timestamp),'%Y%m')
GROUP BY DATE_FORMAT(N.PivotDate,'%Y%m')
In such cases it's common to use a table of dates with all dates (e.g. from 1/1/1970 to 31/12/2999) and LEFT JOIN your data to that table.
See an example in the answer here: mysql joins tables creating missing dates
If you create a dates table you can use:
SELECT
DATE_FORMAT(d.date,'%Y%m') AS `month`, count(rs.rsc_id) AS `counter`
FROM dates d
LEFT JOIN shots as rs
ON d.date = FROM_UNIXTIME(rs.timestamp)
AND rs.rsc_rs_id = 345354
WHERE d.date > DATE_SUB(CURDATE(), INTERVAL 5 MONTH)
AND d.date < CURDATE()
GROUP BY DATE_FORMAT(d.date,'%Y%m');

Categories