php activerecord ORDER BY causes query to fail - php

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

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.

Ignoring Duplicate Records But Bumping Them Up Top

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

select and update mysql same query

I'm running a query to select an array of id's from one table, so that I can update another table with the data from the resulting dataset.
//db query result
$query = "SELECT image_id FROM jos_jxgallery_images ORDER BY jos_jxgallery_images.image_id DESC LIMIT 25";
$query_execute = mysql_query($query);
mysql_close($db_config);
while ($items = mysql_fetch_array($query_execute)) {
echo $items['image_id'];
echo '<br/>';
}
I think I need to do it in the while loop, I just have the echo there to see what's in items variable. That works ok. I think the thing to do is in the while loop..I'd like to replace the 'echoing' with an actual update SET query for my other table. Something like...
while ($items = mysql_fetch_array($query_execute)) {
$q = "UPDATE jx_gallery_images_ratings SET image_id ='".$items."";
mysql_query($q);
But the new table has no data. Is there just a better way to write this...maybe even as one query or something? Any help is appreciated.
EDIT: I should explain a little better. The table is empty, and I could go ahead and use an insert from one table to another just to get the id's there. However, after that...in a way it is somewhat a 'temp' table. But not really. Whatever ordering of image_id's I have created in my SELECT query from my first table (There are other rows to sort by other than image_id, like 'hits', for example)...so the second table needs to be updated with the same ordering of image_id's. Probably be running this several little snippet several times with a cron job. So, yeah, I'm trying to update the second table with the ordering of the SELECT query of the first table and just put the id's in my second table, again...according to the order of the first SELECT query.
If the table is empty, you should do an insert. You can do it in a single query like this:
INSERT INTO jx_gallery_images_ratings (image_id)
SELECT image_id FROM jos_jxgallery_images ORDER BY jos_jxgallery_images.image_id DESC LIMIT 25
Note that you probably wouldn't really need the ORDER BY, adn you could do it for all images at once by removing the LIMIT
Something like:
UPDATE tbl_updateme SET row_to_update = (SELECT row_you_need from tbl_target WHERE tbl_updateme.comparison_row = tbl_target.comparison_row)
INSERT INTO jx_gallery_images_ratings (image_id) (SELECT image_id FROM jos_jxgallery_images ORDER BY jos_jxgallery_images.image_id DESC LIMIT 25)
Or
Easy way is create trigger that updates table after selection with Dynamic SQL

SQL JOINS retrieving and displaying twice

I am joining 2 tables and trying to display the results. Only problem is every result is duplicated. I have 2 tables, messages and follow. Messages are what a certain user inputs, and I want it to display only to the people that follow that certain user.
Messages | Follow
-id -id
-message -mem1 (logged in user)
-userid -mem2 (followed user)
-created
$display ="";
$sql = mysql_query("
SELECT * FROM messages AS me
JOIN follow AS fl
ON me.userid = fl.mem2
WHERE fl.mem1 = $id (logged in user)
ORDER BY me.created
DESC LIMIT 10
") or die(mysql_error());
while($row=mysql_fetch_array($query)){
$msgid = $row["id"];
$message = $row["message"];
$userid = $row["userid"];
$created = $row["created"];
$display .="<?php echo $userid; ?> : <?php echo $message; ?><br />
<?php echo $created; ?>";
}
In the database there are no duplicates, just on the retrieve. Thanks for the input!
Edited: Display Code
You're getting "double" results, most likely because the query results in something different then you expect.
If I understand your table-structure correctly; you have a one-to-many relation from messages to followers.
In your query, however, you fetch combinations of messages and followers. Each line will consist of a unique combination of message<>follower.
In short; when a single message has two followers, you'll get two rows in the result with the same message; but a different follower entry.
If you want to show each message once; and then list all followers per message you can either use group-by functions (e.g group_concat) and group-by on message entries. The other possibility is to fetch the followers in a separate query once you've retrieved the message row, and then print the results from that query as the followers for that message.
If you're simply trying to get the number of followers; you can use a group-by on the UID of your message table and add a count on the UID or user ID of the follower table. (Do not that with group-by, the select * from shouldn't be used; but separate columns can.)
There's really only a few things that could cause the records to duplicate - try breaking down the query into basic components to see if there are more than one record:
SELECT * FROM follow WHERE mem1 = [id];
SELECT * FROM messages WHERE userid = [mem2 from previous result];
If either of the previous statements return more than one record, than the problem lies there. Other than that, I'd look at the PHP code to see if you're doing something there.
As for the query itself, I have a few recommendations:
Place the table with the filter first - the sooner you can narrow the results the better.
Specify a field list instead of using '*' - this will be a tiny bit more efficient, and clarify what you're after. Also, it will give 'DISTINCT' a fighting chance to work...
Here's an example:
SELECT DISTINCT me.id, me.message, me.userid, me.created
FROM follow AS fl
INNER JOIN messages AS me ON me.userid = fl.mem2
WHERE fl.mem1 = :logged_in_user
ORDER BY me.created
DESC LIMIT 10
If you are sure that there are no duplicates and the problem is in the query (you can check that by executing it from your database's interface), you can try two things:
Use the follow table as the leading one:
SELECT messages.*
FROM follow
JOIN messages ON follow.mem2=messages.userid
WHERE follow.mem1=$id
ORDER BY messages.created DESC
LIMIT 0,10;
Use a subquery:
SELECT *
FROM messages
WHERE userid IN(
SELECT DISCTINCT(mem2)
FROM follow
WHERE mem1=$id
)
ORDER BY created DESC
LIMIT 0,10;

select from multiple table with mysql

I had my query set up the other day as so
$query = "SELECT card_id,title,description,meta_description,seo_keywords,price
FROM cards,card_cheapest order by card_id";
As you can see, I was selecting card_id,title,description,meta_description,seo_keywords from the table cards, and price was coming from cheapest_card. They both have the card_id in common (in both tables). However, I ran into a bit of an issue. When I run the query in navicat lite, I receive an error "card_id is ambiguous". Was I doing something wrong?
When 2 or more tables have a column that is named the same, you have to qualify the table you want the column to be from.
i.e.:
$query = "SELECT cards.card_id,title,description,meta_description,seo_keywords,price
FROM cards,card_cheapest order by card_id";
Furthermore, do you really want to run the query this way, without a WHERE/JOIN-clause to define how to JOIN the two tables?
$query = "SELECT cards.card_id,title,description,meta_description,seo_keywords,price
FROM cards,card_cheapest WHERE cards.card_id = card_cheapest.card_id
ORDER BY card_id";
When you have the same column name in two tables you're selecting from, you have to prefix the part in the SELECT with one of the table names (it doesn't matter which if it's the same data)
such as SELECT cards.card_id, ...
EDIT: However, cularis's answer is much more explanatory than mine, and take note about joining the two card_id columns if you want to get correct results.
When you run queries that get information from multiple tables with shared field names you need to specify from which table you want to extract what field. You do this by specifying the table name before the field name.
In your case you have two options:
cards.card_id or card_cheapest.card_id.
Also I agree with #cularis, you are probably better of doing a join, but still you will need to specify which card_id you want to select: the one from cards or card_cheapest.

Categories