PHP: Advanced ORDER BY - php

I have created a real estate website and I wanted to have the listings sorted by the last update and completeness of the listing. So I have been trying to figure out how to sort by a field in mysql (completion_score) in combination with the most recently updated listing. The completion score would be on a 100 point scale with 0 being bad and 100 being perfectly complete. I will have the completion score calculated when the listing is added and updated and saved in the mysql database. I am guessing that I will have to somehow combine the date and the completion_score to make a total, but I am unsure how to do this in one SELECT.
Currently I am using this (which obviously doesn't account for completion score):
ORDER BY ".$wpdb->prefix."fsrep_listings.listing_featured DESC, ".$wpdb->prefix."fsrep_listings.listing_last_updated DESC
I was thinking that if it was completed in the last week I would add 30 points to the completion score, if it was completed in the last month I would add 20 points to the completion score, and if it was completed in the last three months I would add 10 points to the completion score. I could then order it by this updated completion score. The problem is how do I have it change each day to adjust the score.
Taking Mark's advice I put in the following code:
ORDER BY $wpdb->prefix.'fsrep_listings.listing_score' + if($wpdb->prefix.'fsrep_listings.listing_last_updated' > NOW()-INTERVAL 1 WEEK,30,if($wpdb->prefix.'fsrep_listings.listing_last_updated' > NOW()-INTERVAL 1 MONTH,20,if($wpdb->prefix.'fsrep_listings.listing_last_updated' > NOW()-INTERVAL 3 MONTHS,10,0)))' DESC';
I then received the following Parse error: syntax error, unexpected T_IF in /home/...

Your idea sounds good. Why not run with it?
ORDER BY completion_score + IF(date > NOW()-INTERVAL 1 WEEK,30,IF(date > NOW()-INTERVAL 1 MONTH,20,IF(date > NOW()-INTERVAL 3 MONTHS,10,0))) DESC
Something to that effect anyway.

how about something like:
order by completeion_score - (to_days(now()) - to_days(completion_date))/3
or some similar function of the number of days that have passed since completion.
UPDATE
The code I've given you above is SQL only, there is no php involved, therefore everything should be within quotes except for the $wpdb->prefix parts. (This goes for #Mark's answer as well as most of the others that give you code, I'd imagine.)
to add your prefixes, your code should look something like this:
"ORDER BY ".$wpdb->prefix."fsrep_listings.listing_score - (to_days(now()) - to_days(".$wpdb->prefix."fsrep_listings.listing_last_updated))/3"

You need to decide exactly how you want the sorting to work, but if you want you can do ORDER BY completion_date DESC, completion_score DESC, which will give you the most recent days first, within equal dates they'll be ordered by score.

You can think it in reverse way, so that you don't have to update your old entries. Consider the current week 0, then next week 10, next 20 and so on. I think you don't need the QUERY for this :)

Related

Selecting every 100 rows from MySQL witha next button in PHP

I am looking to implement this code into a site but I have a few questions. What does the code mean exactly? How does it translate? "end as x" what is it doing here? does anyone have a recommendation as to how to best use it with php? I found this script on PHP and asked the creator but I want to ask the community to see if I get a quicker response.
To better clarify, I am trying to select every hundred rows. I am trying to create a next button that will pull every 100 rows with every click of the next button or arrow. Like a pagination but without the number of the pages.
SELECT * FROM storeCoins WHERE intId in (SELECT CASE(intId%100=0) WHEN 1 THEN intId else 0 END AS X FROM storeCoins ORDER BY 'year' ASC
I don't understand what the syntax means but would really like to understand this. Seems very efficient. If you can recommend how to best implement this using PHP that would be very helpful. I created a next button that only shows the next id in the database but not the next 100. My biggest interest is in understanding this sql code.
it can be as simple as...
For page 1 use
SELECT * FROM storeCoins ORDER BY 'year' ASC limit 0, 100
for page 2 us
SELECT * FROM storeCoins ORDER BY 'year' ASC limit 99, 100
for page 3 us
SELECT * FROM storeCoins ORDER BY 'year' ASC limit 199, 100
and so on

MySQL sorting date then by part number

Essentially I want these parts (below) grouped then the groups place in order of time, starting from the latest time being at the top of the list.
ID Parts Time
1 SMH_2010 08:59:18
2 JJK_0101 08:59:26
3 FTD_0002 08:59:24
4 JJK_0102 08:59:27
5 FTD_0001 08:59:22
6 SMH_2010 08:59:20
7 FTD_0003 08:59:25
So, the results would look like:
ID Parts Time
1 JJK_0101 08:59:26
2 JJK_0102 08:59:27
3 FTD_0001 08:59:22
4 FTD_0002 08:59:24
5 FTD_0003 08:59:25
6 SMH_2010 08:59:20
7 SMH_2010 08:59:18
Please, I would be grateful for any help.
What you are asking is not sorting in the traditional meaning. Your first attempt orders the result by time, and then by part if multiple timestamps occur at the same time.
What you want neither sorts the result in alphabetically by Parts name, nor ascending/descending on timestamp. What you are asking for can't be accomplished by the sort operation in SQL. Having the parts in sequence is not ordering.
I finally found a solution to this. Not my ideal solution but, never the less it works.
I added another field called max_date which by default is ‘now()’ as every new part is inserted.
I create a prefix from the current part being inserted, something like “SMH_” as a variable called $prefix = “SMH_”;
I have another query that directly follows the insert, which updates the max_date again, by ‘now()’ where the prefix is like $prefix.
UPDATE parts SET max_date = now() WHERE prefix LIKE '%$prefix%'
To display the results I use something along the line of :
SELECT * FROM parts ORDER BY parts.max_date DESC, parts.part ASC

MySQL Queries before NOW

Now I've read on this fantabulous site about how to check if the timestamp that is in your database is before now(), and that answers part of my question.
But the remainder of my question still eludes me:
How can you not only check for timestamps BEFORE now(), but also put a cap on how many before now are queried?
I have a database that is acting as a guestbook, and the output is a flash piece that looks like a post-it board. you fill out a form, and the submission immediately "tacks" itself to the post-it board. The problem is that when you first load the page, it will load every single post starting from id-0 to id-5,000,000 and so on and so forth.
I would like to put a cap on how many are loaded so the query looks at the following things:
What's the current timestamp?
Go back in time (for example) 10 entries ago
Post from THAT point on
The fields I have in my database are: id, comments, timestamp
EDIT
I'm looking at some of the answers, and I would like to ask about the LIMIT. If I put a limit on the queries, will I still be able to query posts that are PAST now?
Example: Say there are two people viewing the site at the same time. One visitor posts a comment into the database. I want person 2 to still be able to the see that comment pop up on his end.
The flash post-it area runs off a php script that queries the database and exports it into an XML format that Flash can read. Every 5 seconds, the flash re-queries the database to check for more posts.
If I put the Limit on the query, will I still be able to grab NEW entries on the fly? I just want the LIMIT to generate a starting point offset from ground zero
I think what you are looking for is called Limit
You just put it at the end of your statement and the query will return the amount of results you wanted
YOUR QUERY LIMIT 0,10
This will return 10 first results
SELECT * FROM
(SELECT ... WHERE dt<NOW() ORDER BY dt DESC LIMIT 10) a
ORDER BY a.dt ASC
or
SELECT ... WHERE dt<NOW() ORDER BY dt DESC LIMIT 10
check which is the more suitable for you.

MySQL Sort by DESC results gap in records. No Missing record w/ sort ASC?

I'm going to refrain from posting my massive code block and just start exactly what I nailed the issued down to.
I'm running this query:
...
SELECT id, Title, images, recdate, 'item' AS type
FROM ads_list
WHERE to_days(now())<= (to_days(recdate)+14)
ORDER BY recdate DESC
LIMIT $offset, $listsperpage
...
This is for a pagination script. My $offset is just a count of the current records position and $listsperpage is set to an arbitrary number per pages (and this is set to 24). So there are supposed to be 24 results per page...
Everything is working perfectly fine EXCEPT, when I run my query in DESC by recdate sort, there are only 23 records outputted in my array on the first page??
And if I run with ASC sort, there are 24 records that display as expected on each page.
My recdate field is formatted like so:
2012-01-14 07:10:33
2012-01-14 07:10:35
2012-01-14 07:10:38
2012-01-14 07:10:30 ...
I also tried to do a DESC sort by id (auto) and still the first result array only contains 23 records, but the total array are all expected records.
I found the "missing" record from the first result is actually pushed forward, so its as if there is just a gap in the results with DESC. And that array is pushed completely forward to the last results page.. So all items are shifted one slot it appears.
I did not want to post up my entire code block because it's a lot, and I've spent a few hours testing and trying variations of my code, so I really think it's something to do with the SQL sort.
I just can't see my DESC would cause this oddity and ASC sort shows as normal.
Finally figured this nightmare out!
I still can't explain why it happens, but at least I am getting full expected results now.
In my while loop, I check the $list["images"] != "". I turns out when using DESC sort on recdate, there is a blank array value, so it evaluates to true and "drops" that listing from the page. So I added $list["images"] == "" and now the image and data displays for that array item.

Popularity Algorithm

I'm making a digg-like website that is going to have a homepage with different categories. I want to display the most popular submissions.
Our rating system is simply "likes", like "I like this" and whatnot. We basically want to display the submissions with the highest number of "likes" per time. We want to have three categories: all-time popularity, last week, and last day.
Does anybody know of a way to help? I have no idea how to go about doing this and making it efficient. I thought that we could use some sort of cron-job to run every 10 minutes and pull in the number of likes per the last 10 minutes...but I've been told that's pretty inefficient?
Help?
Thanks!
Typically Digg and Reddit-like sites go by the date of the submission and not the times of the votes. This way all it takes is a simple SQL query to find the top submissions for X time period. Here's a pseudo-query to find the 10 most popular links from the past 24 hours using this method:
select * from submissions
where (current_time - post_time) < 86400
order by score desc limit 10
Basically, this query says to find all the submissions where the number of seconds between now and the time it was posted is less than 86400, which is 24 hours in UNIX time.
If you really want to measure popularity within X time interval, you'll need to store the post and time for every vote in another table:
create table votes (
post foreign key references submissions(id),
time datetime,
vote integer); -- +1 for upvote, -1 for downvote
Then you can generate a list of the most popular posts between X and Y times like so:
select sum(vote), post from votes
where X < time and time < Y
group by post
order by sum(vote) desc limit 10;
From here you're just a hop, skip, and inner join away from getting the post data tied to the returned ids.
Do you have a decent DB setup? Can we please hear about your CREATE TABLE details and indices? Assuming a sane setup, the DB should be able to pull the counts you require fast enough to suit your needs! For example (net of indices and keys, that somewhat depend on what DB engine you're using), given two tables:
CREATE TABLE submissions (subid INT, when DATETIME, etc etc)
CREATE TABLE likes (subid INT, when DATETIME, etc etc)
you can get the top 33 all-time popular submissions as
SELECT *, COUNT(likes.subid) AS score
FROM submissions
JOIN likes USING(subid)
GROUP BY submissions.subid
ORDER BY COUNT(likes.subid) DESC
LIMIT 33
and those voted for within a certain time range as
SELECT *, COUNT(likes.subid) AS score
FROM submissions
JOIN likes USING(subid)
WHERE likes.when BETWEEN initial_time AND final_time
GROUP BY submissions.subid
ORDER BY COUNT(likes.subid) DESC
LIMIT 33
If you were storing "votes" (positive or negative) in likes, instead of just counting each entry there as +1, you could simply use SUM(likes.vote) instead of the COUNTs.
For stable list like alltime, lastweek, because they are not supposed to change really fast so that I think you should save the list in your cache with expiration time is around 1 days or longer.
If you concern about correct count in real time, you can check at every page view by comparing the page with lowest page in the cache.
All you need to do is to care for synchronizing between the cache and actual database.
thethanghn
Queries where the order is some function of the current time can become real performance problems. Things get much simpler if you can bucket by calendar time and update scores for each bucket as people vote.
To complete nobody_'s answer I would suggest you read up on the documentation (if you are using MySQL of course).

Categories