sorting groups within a query - php

I am using the below query to paginate posts on my site:
select * from songs t1 join (
select to_days(date) day from songs
group by day
order by day desc
limit $start_row, $items_per_page
) t2
on to_days(t1.date) = t2.day
Depending on my $start_row and $items_per_page this will return all the posts for say, the last 7 days. Regardless of if there was more than 1 post per day or a day is empty and skipped.
For example:
Above the query has correctly returned all the posts from the latest 7 days. Today. Yesterday. The day before that and so on...
However if you look at the table id 12## values on the far left, and time stamp day values 73#### on the far right. You will see they are grouped backwards.
How do I switch this query around so that it returns the same results in the same grouping but in a reverse order?
For example:
Oh My! - Run This Town(TMS remix)
Lost Mapaches-Back To Basics (La Royale Remix)
Dimitri from Paris & DJ Rocca-I Need A Reason For LIving (Radio Mix)
Chromeo - Hot Mess (23 Dubstep Remix)
and so on... I tried removing the desc value but that just returns the grouping from the oldest entries in the table.

You need to add an ORDER BY to the outer select as well, not just the inner one being JOINed to.
SELECT *
FROM songs t1
JOIN (
SELECT to_days(date) day FROM songs
GROUP BY day
ORDER BY day DESC
LIMIT $start_row, $items_per_page
) t2 ON to_days(t1.date) = t2.day
ORDER BY day DESC
(That last line is the bit you need to add.)

I would order your data on the outside of the subquery (note the last line), please adjust last line for asc / desc or if you want to order by.
select * from songs t1 join (
select to_days(date) day from songs
group by day
order by day desc
limit $start_row, $items_per_page
) t2
on to_days(t1.date) = t2.day
order by id desc

Related

MySQL query rows with defined date interval

I have no idea how to solve the following problem: I have several rows in my database with one timestamp per row. Now I would like to filter all rows for entries until the date interval for any two dates is bigger than 30 days. I have no defined date interval for specific dates, like between 12/01/2017 and 11/01/2017, that would be easy, even for me. All I know is that the timestamp interval from one row to the next row (query must be sorted by timestamp desc) must not be bigger than 30 days.
Please see my db at http://sqlfiddle.com/#!9/55a521/2
In this case the last entry shown should be the one with id 65404844. I would appreciate if you might give me a small hint for this.
Thank you very much!
You can use this query to build a filter.
SELECT
t.id,
from_unixtime(timestamp)
, IF(#pt < timestamp - 30*24*60*60, 1, 0) AS filter
, #pt := timestamp
FROM
t
, (SELECT #pt := MIN(timestamp) FROM t) v
ORDER BY timestamp
see it working live in an sqlfiddle
Important here is to order by timestamp. Then you initialize the #pt variable with the lowest value. Another important thing is to have the select clause in the right order.
First you compare the current record with the variable in the IF() function. Then you assign the current record to the variable. This way when the next row is evaluated, the variable still holds the value of the previous row in the IF() function.
To get the rows you want, use above query in a subquery to filter.
SELECT id, ts FROM (
SELECT
t.id,
from_unixtime(timestamp) as ts
, IF(#pt < timestamp - 30*24*60*60, 1, 0) AS filter
, #pt := timestamp
FROM
t
, (SELECT #pt := MIN(timestamp) FROM t) v
ORDER BY timestamp
) sq
WHERE sq.filter = 1
This filters out the rows that have a more than 30 days difference from the previous rows. (1st solution) - only works if the id column has consecutive values
SELECT t.id, t.timestamp, DATEDIFF(FROM_UNIXTIME(t1.timestamp), FROM_UNIXTIME(t.timestamp)) AS days_diff
FROM tbl t
LEFT JOIN tbl t1
ON t.id = t1.id + 1
HAVING days_diff <= 30
ORDER BY t.timestamp DESC;
This filters all the results that are within 30 days of each of the other entries.
SELECT *
FROM tbl t
WHERE EXISTS (
SELECT id
FROM tbl t1
WHERE DATEDIFF(FROM_UNIXTIME(t1.timestamp), FROM_UNIXTIME(t.timestamp)) < 30
AND t1.id <> t.id
)
ORDER BY t.timestamp desc;

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;

PHP and SQL - How to select highest sum of all months in a current year?

So I have table 'item' in database with attributes: id, dateItem, price.
I want to find MAX(SUM(price)) for some month in a current year.
id dateItem (Format: yyyy-mm-dd) price
1 25.06.2015. 986,69
2 21.06.2015. 1564
3 22.03.2015. 23,56
4 21.03.2015. 187,23
5 01.03.2015. 489,33
6 06.10.2015. 975,26
I came up with something like this, but I know it's not ok. Please, help :s
$sql = "SELECT MAX(SUM(price)) FROM item WHERE DATE('Y') = 2015 AND
dateItem between DATE('Y/m/1') and DATE('Y/m/31')";
You can't nest aggregation functions. You need to use a subquery.
SELECT MAX(pricesum)
FROM (SELECT SUM(price) AS pricesum
FROM item
WHERE YEAR(dateItem) = YEAR(NOW())
GROUP BY MONTH(dateItem)) AS subquery
You can do this with ORDER BY and LIMIT:
SELECT SUM(price) AS pricesum
FROM item
WHERE YEAR(dateItem) = YEAR(NOW())
GROUP BY MONTH(dateItem)
ORDER BY pricesum DESC
LIMIT 1;
If you want to know the month as well, you can include that in the SELECT clause.

MySQL - Getting data for week ahead

I have this sql query:
SELECT
"bookings"."customerID",
"bookings"."arrivalDate",
"bookings"."leavingDate",
"bookings"."bookingID",
"bookings"."pickup",
"bookings"."dropoff",
"bookings"."locationID",
"locations"."locationName",
"customers"."customerName"
FROM
"bookings"
LEFT JOIN "customers" ON
"bookings"."customerID" = "customers"."customerID"
LEFT JOIN "locations" ON
"bookings"."locationID" = "locations"."locationID"
WHERE (
"bookings"."arrivalDate" BETWEEN '2014-11-15' AND '2014-11-22'
)
What i'm hoping to get is all the bookings for the week ahead. Sorted by oldest first. Just cant get it to work!
SELECT
b.customerID,
b.arrivalDate,
b.leavingDate,
b.bookingID,
b.pickup,
b.dropoff,
b.locationID,
l.locationName,
c.customerName
FROM
bookings b
LEFT JOIN customers c
ON b.customerID = c.customerID
LEFT JOIN locations l
ON b.locationID = l.locationID
WHERE
b.arrivalDate > curdate()
AND b.arrivalDate <= date_add( curdate(), INTERVAL 7 DAY )
order by
b.leavingDate DESC
I updated to utilize aliases vs long table name references. Also, the where clause to make use of the current date and 7 days forward to get the week ahead so it is not hard-referenced. You could additionally adjust in case you wanted the query always to be based on a Sat or Sun of a given week.
As for the sorting by the "oldest" first... oldest in what way... just change the order by clause. I am GUESSING your intent was on the date leaving out... So by that column DESCENDING would put the oldest LEAVING item at the top of the list.

Combining two MYSQL Queries into a single one

I am trying to combine two MYSQL Queries into one. What I want to do is select the first and last row added for each day and subtract the last column for that day from the first column of that day and output that. What this would do is give me a net gain of XP in this game for that day.
Below are my two queries, their only difference is ordering the date by DESC vs ASC. the column in the database that i want to subtract from each other is "xp"
$query = mysql_query("
SELECT * FROM (SELECT * FROM skills WHERE
userID='$checkID' AND
skill = '$skill' AND
date >= ".$date."
ORDER BY date DESC) as temp
GROUP BY from_unixtime(date, '%Y%m%d')
");
$query2 = mysql_query("
SELECT * FROM (SELECT * FROM skills WHERE
userID='$checkID' AND
skill = '$skill' AND
date >= ".$date."
ORDER BY date DESC) as temp
GROUP BY from_unixtime(date, '%Y%m%d')
");
SELECT FROM_UNIXTIME(date, '%Y%m%d') AS YYYYMMDD, MAX(xp)-MIN(xp) AS xp_gain
FROM skills
WHERE userID = '$checkID'
AND skill = '$skill'
AND date >= $date
GROUP BY YYYYMMDD
This assumes that XP always increases, so it doesn't need to use the times to find the beginning and ending values.
If that's not a correct assumption, what you want is something like this:
SELECT first.YYYYMMDD, last.xp - first.xp
FROM (subquery1) AS first
JOIN (subquery2) AS last
ON first.YYYYMMDD = last.YYYYMMDD
Replace subquery1 with a query that returns the first row of each day, and subquery2 with a query that returns the last row of each day. The queries you posted in your question don't do this, but there are many SO questions you can find that explain how to get the highest or lowest row per group.

Categories