Ignoring Duplicate Records But Bumping Them Up Top - php

I am making a feed system similar to the way facebook works now what I am trying to implement is the duplicate functionality.
if a user writes the same post= then don't display it duplicatly as PHP normally does by default but bump it up the top so users knows another user as re-wrote it
Here's my query
$select_posts_from_groups_query = $db->query("SELECT * FROM spud_groups_posts LEFT JOIN spud_groups_members
ON spud_groups_posts.group_url = spud_groups_members.gurl WHERE member_name='$mybb_username' GROUP BY post_body ORDER BY time_posted DESC" );
how can I get it to bump it self as the latest update once a user re duplicates it it would let users know that some one else has shared it
Thanks ;)

Three solutions
Assuming you have a update timing field on your data record called time_updated, there are a couple of things you could do:
you could simply max the two:
ORDER BY max(time_posted,time_updated) DESC
This might give issues with NULL values though
substitute NULLs in the time_updated
ORDER BY nvl(time_updated, time_posted) DESC
(Oracle sql syntax nvl() substitutes NULL in the 1st param with the 2nd param - don't know what DB you are using)
always store time_updated (the best solution IMO). When creating the post (initially) set time_updated = time_created AND use
ORDER BY time_updated DESC

Related

Select data from one table, arrange by a sum of data from another

A client is looking for a points system to be implemented on her website, I'm struggling to display the users based upon the amount of points collected, I hope somebody may be able to help me out here and point me in the right direction to getting this code to work properly.
I am selecting all data from ap_users and in the code I am also trying to select all data from ap_points although I do not require all the data from either tables, to be specific I only require:
ap_users:
user_id
first_name
last_name
display_img
hub_access
ap_points:
user_id
points_added
I thought that selecting ALL data may be the easiest route, will let you decide.
I am trying to select and display all users where hub_access = '1' and order by the total points_added by highest first. Points are added separately by rows and need to be added up (which is why I have the sum function).
$sql = "SELECT * FROM `ap_users`, `ap_points` WHERE `hub_access` = '1' ORDER BY sum(points_added) DESC";
I also tried configuring it to be specific tables like:
ap_users.hub_access and ORDER BY sum(ap_points.points_added) but these did not work either.
This current code is either showing no results or a single result with no errors displaying? I'm not sure whether I may need to use some kind of Group By function to connect the user_ids from both tables ?
SUM is an aggregating function. You should be grouping by user_id if you want the sum for each user_id.
Something like
SELECT *, sum(points_added) as sum_points FROM app_users
JOIN app_points ON app_users.user_id = app_points.user_id
WHERE `hub_access` = '1'
GROUP BY app_users.user_id
ORDER BY sum_points;
I have not tested that query, but that should give you an idea of the solution.

Return all records of non-given id if just one of those records matches the given id of another field

After searching for a damn long time, I've not found a query to make this happen.
I have an "offers" table with a "listing_id" field and a "user_id" field and I need to get ALL the records for all listing_id's where at least one record matches the given user_id.
In other words, I need a query that determines the listing_id's that the given user is involved in, and then returns all the offer records of those listing_id's regardless of user_id.
That last part is the problem. It's getting all the other user's offer records to return when I'm only providing one user's id and no listing id's
I was thinking of first determining the listing_ids in a separate query and then using a php loop to create a WHERE clause for a second query that would consist of a bunch of "listing_id = $var ||" but then I couldn't bring myself to do it because I figured there must be a better way.
Hopefully this is easy and the only reason it has escaped me is because I've had my head up my ass. Will be happy to get this one behind me.
Thanks for taking the time.
Josh
You could do two queries playing along on the MySQL side, like this:
SELECT * FROM offers WHERE listing_id IN (SELECT listing_id FROM offers WHERE user_id = 1)
If I understand what you are after you should join offers on itself on listingid match and userid = given
select * from offers AS t1
inner join offers AS t2 on t1.listingid = t2.listingid and t1.userid = 1;

php activerecord ORDER BY causes query to fail

I have a codeigniter project that uses php active record. there are 3 tables (users,punches,and jobs) When I run this query
$records = Punches::find_by_sql("Select * from jobs,users,punches where jobs.job_id = $job_id AND punches.job_id = $job_id AND punches.id= users.id AND NOT ISNULL(end_time) ORDER BY last_name,id ");
the query fails. If I take the order by out it works just fine. Please note I've used every variation of ORDER BY I can think of.
Since you are joining multiple tables, you need to specify which tables columns you are using when the column is not unique. In your case you need to specify which table the id column is from.
be spesific for id in your order by id, because users and punches tables have id too
$records = Punches::find_by_sql("... ORDER BY last_name, TABLENAME.id");
Thanks to whoever suggested that I run it in phpmyadmin... that helped to spot the error quickly. I needed tablename.id

Advanced MySQL ORDER BY

I am making a basic forum using PHP and MySQL. I am using one table for all of the threads. It is named forum_posts. It has these fields:
id, creator, time, title, message, thread_reply, forum_id, locked, sticky
If the post is a new thread, then thread_reply is set to 0. Otherwise, thread_reply is set to the id of the thread that this post is replying to. On the page that shows all of the threads, I want to order the threads by the time of the last post that was replied to it. I am using this query:
SELECT `id`, `title`, `creator` FROM `forum_posts` WHERE `thread_reply` = 0 AND `forum_id` = 1 ORDER BY -`time`
The only problem is that query only orders by the time the thread was created, instead of the time the last reply was to the thread. If you don't understand what I am talking about, go look at the home page of any forum and look how it orders the threads by the time of the last post to the thread, not the time the thread was created.
I made a custom forum last week (as phpbb just didn't suit my needs).
I would first advise the following structure:
table for users
table for categories (main sections of forum)
table for threads (these are inside categories)
table for posts (these are in individual threads)
To order the posts by the last action, I simply created a field in the Threads table that was called last_action or something along those lines.
Then, when the thread is first created, I set that value to the date it was created. Then, whenever a post is edited or a new post is added to that thread, that value updates. This then means you just do:
SELECT blah, blah, blah FROM threads WHERE cat=4 ORDER BY last_action DESC
Hopefully that helps you.
Easiest way is probably to make it so that instead of using the test thread_reply=0, you use the test thread_reply=id. Make a thread starting-thread be a reply to itself. If you use that for something else it might make it a bit more messy, but you can thus do something like
SELECT * FROM
(SELECT `id`, `title`, `creator`, b.rtime FROM `forum_posts`
WHERE a.`thread_reply` = a.`id` AND `forum_id` = 1 ) a
LEFT JOIN (SELECT `thread_reply`, MAX(`time`) rtime FROM `forum_posts`
WHERE `forum_id`=1
GROUP BY `thread_reply`) b ON a.`id`=b.`thread_reply`
ORDER BY `rtime` DESC
Note that the first subquery is unnecessary, however it is probably more efficient to first filter by forum and "is it a first post".
Also, why use ORDER BY -time ASC when you could use ORDER BY time DESC?
But yes, the best way is probably just to have a table for topics, and a table for replies. (First reply in a topic is the first post; the topic itself has no inherent body text)
Use
SELECT `op`.`id`, `op`.`title`, `op`.`creator`
FROM `forum_posts` `op`, `forum_posts` `rep`
WHERE (`op`.`thread_reply` = 0 OR `op`.`thread_reply` = `rep`.`id`)
AND `op`.`forum_id` = 1
ORDER BY IF(`op`.`thread_reply` = 0, -`op`.`time`, -`rep`.`time`)
Basically what I do here is find the reply if applicable and order by its time.
If you have the possiblity:
Create two tables:
Threads: id, subject, date_created, date_last_reply, ..
Posts: id, thread_id, date, ..
SELECT * FROM threads ORDER BY date_last_reply
As you're only getting the "start" post with that query you've got no way to order by the latest reply. You need to add another column (last_reply_time etc) and have your application update that field every time a new thread is posted, and then order by that.

Assign places in the rating (MySQL, PHP)

I have a MySQL database with the following columns:
id company rating_score rating_place
I have companies and rating scores for each company. So, my db looks like:
id company rating_score rating_place
75 Intel 356.23
34 Sun 287.49
etc.
How can I assign the places (my rating_place column is empty) based on the score using php and mysql?
Thank you!
While Andrew G. Johnson is correct, you may not need to even store this information in the database.
The answer I have for you is simple: "Why do you want to store this in the database?"
If you have actually have a good reason, then you have a few choices based on how static the data is. If the data is created then inserted all at once, then ORDER BY rating_score DESC at the end of your statement should do it (if rating_place is assigned automatically from 1).
Otherwise, I would do something in a dedicated PHP page that, once your 2 columns are read, assigns the rating_place. If you manually enter data into your database, it shouldn't hurt to have to open the page. If data collection is automated, go ahead and throw a call to the "update_places_page" that updates the rating.
Edit:
Another option is just to create a view for rating_score that takes the top 20 and orders reorders them, then select from the new view and the actual table based on rating_score.
If you are just trying sort by highest rating to lowest add this to the end of your SQL query:
ORDER BY rating_score DESC
Or lowest to highest:
ORDER BY rating_score ASC
If you still want to do this your way [which I'd advise against] try this:
UPDATE mytable SET rating_place=(SELECT COUNT(*)+1 FROM mytable tablecheck WHERE tablecheck.rating_score > mytable.rating_score)
How about this:
update mytable set rating_place =(select count(*)+1 from mytable intb where intb.rating_score>mytable.rating_score)
----edit (after comment)
aww sorry, you can't select from the same table that you're updating in mysql, so try it with a temp table:
create table mytemptable as
select #row := #row +1 as place, mytable.id
from mytable, (SELECT #row := 0) r
order by rating_score desc;
and then just a similar update:
update mytable set rating_place = (
select place
from mytemptable
where mytemptable.id=mytable.id
)
after that you can drop that mytemptable.
although if you want to avoid a separate table and you can use php, you can try
$res=mysql_query("select id from mytable order by rating_score desc");
$ratings=array();
while ($r=mysql_fetch_assoc($res)) {
$ratings[]=$r['id'];
}
foreach ($ratings as $key=>$val) {
mysql_query("update mytable set rating_score=".($key+1)." where id=".$val);
}
Just sort by rating! This approach is just wrong as you would have to shift modify all data above a certain rank if you insert something. Bad data structure.
Well if you only insert something once or twice a year you could argue that integer sorting is faster, but well thats just a very minimal difference as sorting is based on Tree indexes and not on comparision.
So I have seen solutions like Andrew G. Johnson's. You could also tweak this further and only update entries with a higher score.
You could also create a trigger that does it automatically for you.
But let me explain why this is wrong:
Its redundant data. Its not atomic and consistent.
In a good atabase design you should always (if possible) store every information only at one point so it can be modified, deleted in an atomic way.
So you can avoid any inconsistencies and complications in the first place.
If you really wan't to "cache" the ranking, do it in your application.
So what are your alternatives to this if you really want to have database fields called like this?
Create a mysql view based on the sorted query.
You can also do caching there AFAIK if thats your goal.
But the better option for caching would be just to let the mysql query cache do the work for you. That would be the very best option.
I see no reason what so ever to do what you are trying to do, only valid arguments against it.
SELECT #row := 0;
UPDATE
`table`
SET
`table`.`rating_place` = (#row := #row +1)
ORDER BY
`table`.`rating_score` DESC;
PS: If you will be sending the queries from PHP, you will need to split the two, since PHP MySQL extension normally allows only single query per call.
yourQueryFunc('SELECT #row := 0;');
yourQueryFunc('
SELECT #row := 0;
UPDATE
`table`
SET
`table`.`rating_place` = (#row := #row +1)
ORDER BY
`table`.`rating_score` DESC;');
I would do a select using the order by desc clause and then update each row with the rating.
It is probably a lot more convenient to work out the place as you go. To do this you would read the values and order by Rating_Score (ASC). Then they would be in order of place as you read them out. If you like, you could then write this back into the table, but this would mean you have to constantly update the place value. If this database is going to be constantly changing from user input or something, I would recommend working out the places as you go. If the table will remain mostly static, you could have a place column.

Categories