I have this query:
SELECT a.id as alert_id,a.user_id,a.date,a.msg_title,a.message,a.alert_type,a.school_or_contact_id,
u.id as user_id, u.full_name,
c.id as contact_id, concat(c.f_name,' ',c.l_name) as contact_name
FROM alerts a
LEFT OUTER JOIN users u ON a.user_id = u.id
LEFT OUTER JOIN contacts c ON a.school_or_contact_id = c.id
LEFT OUTER JOIN schools s ON a.school_or_contact_id = s.school_id
ORDER BY a.date
This works, but I need it to do one more thing, and I can't seem to figure it out. I need to select some data from the "schools" table IF data in alerts.alert_type (alerts table) == "claim".
If "claim" is not found in alerts.alerts_table, then it needs to do nothing different than the query above. alerts.alert_table
This is what I've tried, but it doesn't seem to work:
SELECT a.id as alert_id,a.user_id,a.date,a.msg_title,a.message,a.alert_type,a.school_or_contact_id,
u.id as user_id, u.full_name,
c.id as contact_id, concat(c.f_name,' ',c.l_name) as contact_name,
IF(a.alert_type = 'claim', select s.* from schools where school_id = a.school_or_contact_id)
FROM alerts a
LEFT OUTER JOIN users u ON a.user_id = u.id
LEFT OUTER JOIN contacts c ON a.school_or_contact_id = c.id
LEFT OUTER JOIN schools s ON a.school_or_contact_id = s.school_id
ORDER BY a.date
EDIT
For clarification, I'm building a tool that has front page "update" kind of like Facebook. Depending on what the users are doing, the "alerts" will say different things.
The schools table has 3,000 rows and will only apply to the alerts table when the row alerts_type.alerts == "claim". Otherwise, it won't matter what what's in the schools table. If alert_type.alerts != "claim", the "contacts" table will be where the rest of the data comes from.
I wanted to have cleaner data when doing the query (ie -- not "school" table data when alerts_type.alerts != "claim") but I can easily do this in PHP. I just didn't want to pull data that I wouldn't use.
Thank you everyone for all the help and advice!
2nd edit
I will change the table schema. Right now, it looks like this:
mysql> desc alerts;
+----------------------+--------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+--------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(12) | YES | | NULL | |
| date | timestamp | NO | | CURRENT_TIMESTAMP | |
| msg_title | varchar(100) | YES | | NULL | |
| message | longtext | YES | | NULL | |
| alert_type | varchar(255) | YES | | NULL | |
| school_or_contact_id | int(12) | YES | | NULL | |
+----------------------+--------------+------+-----+-------------------+----------------+
7 rows in set (0.00 sec)
I will edit the alerts table to this (below), then JOIN alerts.school_id = schools.school_id. This should fix the problem.
+----------------------+--------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+--------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(12) | YES | | NULL | |
| date | timestamp | NO | | CURRENT_TIMESTAMP | |
| msg_title | varchar(100) | YES | | NULL | |
| message | longtext | YES | | NULL | |
| alert_type | varchar(255) | YES | | NULL | |
| school_id | int(12) | YES | | NULL | |
| contact_id | int(12) | YES | | NULL | |
+----------------------+--------------+------+-----+-------------------+----------------+
You can't really do an optional JOIN like you're trying in the above SQL.
You'll need an IF clause for each column, i.e IF (a.alert_type = 'claim', s.col, NULL)
As you've already joined on the schools table, there shouldn't be any difference in performance, and fetching data all in one query will be better than running multiple queries.
An example:
SELECT a.id as alert_id,a.user_id,a.date,a.msg_title,a.message,a.alert_type,a.school_or_contact_id,
u.id as user_id, u.full_name,
c.id as contact_id, concat(c.f_name,' ',c.l_name) as contact_name,
IF (a.alert_type = 'claim', s.col1, NULL) AS col1,
IF (a.alert_type = 'claim', s.col2, NULL) AS col2
FROM alerts a
LEFT OUTER JOIN users u ON a.user_id = u.id
LEFT OUTER JOIN contacts c ON a.school_or_contact_id = c.id
LEFT OUTER JOIN schools s ON a.school_or_contact_id = s.school_id
ORDER BY a.date
If it happens that you have a lot of fields in the schools table you might as well just fetch s.*, avoid the IF parts, and simply skip over those values in your PHP script.
Probably the best way would be to check the alert_type using PHP and run a second query if needed. You could then merge the two results together.
You might try this though:
SELECT a.id as alert_id,a.user_id,a.date,a.msg_title,a.message,a.alert_type,a.school_or_contact_id,
u.id as user_id, u.full_name,
c.id as contact_id, concat(c.f_name,' ',c.l_name) as contact_name, s.*
FROM alerts a
LEFT OUTER JOIN users u ON a.user_id = u.id
LEFT OUTER JOIN contacts c ON a.school_or_contact_id = c.id
LEFT OUTER JOIN schools s ON a.school_or_contact_id = s.school_id AND a.alert_type = 'claim'
ORDER BY a.date
You can't embed queries into IF() calls. Any reason you can't just do the sub-query unconditionally and then filter the value in your client app? Regardless of this, you cannot have a subquery return multiple fields as you are when the subquery is substituting for a field. So even if the IF() call were possible, the sub-queries have to return a single field/row.
Let me introduce you to UNION SELECT.
Note this will be a long query, and depends on the exact structure of schools; the below assumes two columes xs.foo and xs.bar:
SELECT * FROM
(SELECT a.id as alert_id,a.user_id,a.date,a.msg_title,a.message,
a.alert_type,a.school_or_contact_id,
u.id as user_id, u.full_name,
c.id as contact_id, concat(c.f_name,' ',c.l_name) as contact_name,NULL,NULL
FROM alerts a
LEFT OUTER JOIN users u ON a.user_id = u.id
LEFT OUTER JOIN contacts c ON a.school_or_contact_id = c.id
WHERE xa.alert_type!='claim'
UNION SELECT xa.id as alert_id,xa.user_id,xa.date,xa.msg_title,xa.message,
xa.alert_type,xa.school_or_contact_id,
xu.id as user_id, xu.full_name,
xc.id as contact_id, concat(xc.f_name,' ',xc.l_name) as contact_name,xs.foo,xs.bar
FROM alerts xa
LEFT OUTER JOIN users xu ON xa.user_id = xu.id
LEFT OUTER JOIN contacts xc ON xa.school_or_contact_id = xc.id
LEFT OUTER JOIN schools xs ON xa.school_or_contact_id = xs.school_id
WHERE xa.alert_type='claim')
ORDER BY date
A caveat: That this is complicated is a good sign your database is poorly designed. If you inherited this...problem, then so be it, but if you're creating new code that works this way, let me strongly recommend that you model your data so a full outer join does the right thing.
As others explained, it's notpossible to have variable number of columns in a result set.
The closest you can get to what you want may be this:
SELECT a.id as alert_id
, a.user_id
, a.date
, a.msg_title
, a.message
, a.alert_type
, a.school_or_contact_id
, u.id as user_id
, u.full_name
, c.id as contact_id
, concat(c.f_name,' ',c.l_name) as contact_name
, s.*
FROM alerts a
FROM alerts a
LEFT OUTER JOIN users u
ON a.user_id = u.id
LEFT OUTER JOIN contacts c
ON a.school_or_contact_id = c.id
LEFT OUTER JOIN schools s
ON a.school_or_contact_id = s.school_id
AND a.alert_type = 'claim'
ORDER BY a.date
Related
I have a MySQL table of comments, like this:
+------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+----------------+
| userid | int(11) | NO | | 0 | |
| comment | char(255) | NO | | NULL | |
| content | int(11) | NO | MUL | 0 | |
| ratings | int(11) | NO | | 0 | |
| datetime | datetime | NO | | NULL | |
| ip | int(10) unsigned | NO | | NULL | |
| is_updated | tinyint(2) | NO | | 0 | |
| record_num | int(11) | NO | PRI | NULL | auto_increment |
+------------+------------------+------+-----+---------+----------------+
Now I can fetch comments from this and usernames from another table using an INNER JOIN query like this.
I can get the top the three comments ORDER BY comments.ratings DESC:
SELECT comments.userid, users.username, comments.comment, comments.ratings, comments.datetime, comments.record_num , content.uploader , content.anonymous
FROM comments
LEFT JOIN users ON comments.userid = users.record_num
LEFT JOIN content ON comments.content = content.record_num
WHERE comments.content = ? ORDER BY comments.ratings DESC limit 3
and
Getting regular comments ORDER BY comments.datetime DESC
SELECT comments.userid, users.username, comments.comment, comments.ratings, comments.datetime, comments.record_num , content.uploader , content.anonymous
FROM comments
LEFT JOIN users ON comments.userid = users.record_num
LEFT JOIN content ON comments.content = content.record_num
WHERE comments.content = ? ORDER BY comments.datetime DESC limit ?, ?
I am trying show users the top three comments by their ratings at first and then regular comments order by comments.datetime DESC .
Now how can I join the above two MySQL queries into one?
As the other answer says - you can combine results using union - which simply means to join two results together. What is important to note, however, is that you can't simply union those two queries together directly, as they use order by, so we need to wrap them in outer queries, and use a ranking variable to ensure we can reconstruct the union in the order that we want:
select * from (
SELECT 1 as tbl,
comments.userid,
users.username,
comments.comment,
comments.ratings,
comments.datetime,
comments.record_num,
content.uploader,
content.anonymous,
#rank := #rank + 1 as rank
FROM comments
LEFT JOIN users ON comments.userid = users.record_num
LEFT JOIN content ON comments.content = content.record_num
CROSS JOIN (select #rank := 0 ) q
WHERE comments.content = ? ORDER BY comments.ratings DESC limit 3
) q1
UNION ALL
select * from (
SELECT 2 as tbl,
comments.userid,
users.username,
comments.comment,
comments.ratings,
comments.datetime,
comments.record_num,
content.uploader,
content.anonymous,
#rank := #rank + 1 as rank
FROM comments
LEFT JOIN users ON comments.userid = users.record_num
LEFT JOIN content ON comments.content = content.record_num
CROSS JOIN (select #rank := 0 ) q
WHERE comments.content = ? ORDER BY comments.datetime DESC limit ?, ?
) q2
ORDER BY tbl asc, rank asc;
union by default is distinct meaning that it won't duplicate rows found in both result sets, however there is also no guarantee that the rows will be returned in the order you expect, hence the need to mark each table with its own tbl value, and then order by that field.
If you were certain there would be no duplicates, you could eliminate the duplicate check by using union all, instead of union
To answer your question, yes you can combine your queries using UNION, but
I am trying show users the top three comments by their ratings at first and then regular comments order by comments.datetime DESC
If your are trying to achieve something like the functionality of comments of Stack Overflow, where the top comments (or comments with upvotes) are showed first, then I think separate queries are good enough.
If your query is combined, then the user is required to load all the top and regular comments. Also, it is somehow hard to make or implement a pagination with big query that have UNION (based on my experience because I'm still a noob on coding).
Disclaimer: it is hard, but not impossible
If I'm the one who is going to code that problem, first my program will load the top three comments. After that, there is a 'Show more comments' button that will post to my server using Ajax and append the result (regular comments) to the list of showed comments. With that, queries need to be separate like what you have now.
To stack result sets on top of each other into one set, you need to use a "UNION" - https://dev.mysql.com/doc/refman/5.0/en/union.html
I have Joomla tables (shown bellow) with some records in it (records are about companies). What I want to achieve is to get all records and group them to new table (I am using PHP for this). Problem is that there is 548 records (companies) and I got 439 records (after grouping).
Does someone knows where's the problem?
Here is database:
And here is query:
SELECT a.itemid as ID, a.title as Name, c.name as Categories, d.data_txt as Description, d.fieldid as FieldID FROM `jos_sobi2_item` as a
INNER JOIN `jos_sobi2_cat_items_relations` as b ON b.itemid=a.itemid
INNER JOIN `jos_sobi2_categories` as c ON c.catid = b.catid
INNER JOIN `jos_sobi2_fields_data`as d ON a.itemid=d.itemid
The issue is inner join is filtering out the records which are not in the related tables but in jos_sobi2_item
You may want to do left join something as
select
a.itemid as ID,
a.title as Name,
c.name as Categories,
d.data_txt as Description,
d.fieldid as FieldID
FROM `jos_sobi2_item` as a
left join `jos_sobi2_cat_items_relations` as b ON b.itemid=a.itemid
left join `jos_sobi2_categories` as c ON c.catid = b.catid
left join `jos_sobi2_fields_data`as d ON a.itemid=d.itemid
Here is an illustration of this
create table table1 (t1id int , name varchar(100));
insert into table1 values (1,'aa'),(2,'cc'),(3,'dd'),(4,'ee'),(5,'ff'),(6,'bb'),(7,'gg');
create table table2 (t2id int, description varchar(100));
insert into table2 values (1,'desc1'),(2,'desc2'),(3,'desc3');
create table table3 (t3id int, t1id int , t2id int);
insert into table3 values (1,1,2),(2,3,2),(3,2,2),(4,7,3);
create table table4 (t4id int , t1id int ,fieldid int);
insert into table4 values (1,1,10),(2,3,23),(3,4,34),(4,5,50);
select
t1.t1id,
t1.name,
t2.description,
t4.fieldid
from table1 t1
left join table3 t3 on t3.t1id = t1.t1id
left join table2 t2 on t2.t2id = t3.t2id
left join table4 t4 on t4.t1id = t1.t1id;
+------+------+-------------+---------+
| t1id | name | description | fieldid |
+------+------+-------------+---------+
| 1 | aa | desc2 | 10 |
| 2 | cc | desc2 | NULL |
| 3 | dd | desc2 | 23 |
| 4 | ee | NULL | 34 |
| 5 | ff | NULL | 50 |
| 6 | bb | NULL | NULL |
| 7 | gg | desc3 | NULL |
+------+------+-------------+---------+
The above example is similar to what you have.
If you still want to use INNER
1. Try a LEFT JOIN instead a INNER JOIN, and put a condition in WHERE
SELECT a.itemid as ID, a.title as Name, c.name as Categories, d.data_txt as Description, d.fieldid as FieldID FROM `jos_sobi2_item` as a
LEFT JOIN `jos_sobi2_cat_items_relations` as b ON b.itemid=a.itemid
LEFT JOIN `jos_sobi2_categories` as c ON c.catid = b.catid
LEFT JOIN `jos_sobi2_fields_data`as d ON a.itemid=d.itemid
WHERE b.itemid IS NULL OR c.catid IS NULL OR d.itemid IS NULL
Look at your results and see where you have nulls, after that you will discover what records from the jos_sobi2_item don't have a connection in the other tables.
Or if you want to use LEFT JOIN :
1.Run the query:
SELECT a.itemid as ID, a.title as Name, c.name as Categories, d.data_txt as Description, d.fieldid as FieldID,
COUNT(b.itemid), COUNT(c.catid), COUNT(d.itemid)
FROM `jos_sobi2_item` as a
LEFT JOIN `jos_sobi2_cat_items_relations` as b ON b.itemid=a.itemid
LEFT JOIN `jos_sobi2_categories` as c ON c.catid = b.catid
LEFT JOIN `jos_sobi2_fields_data`as d ON a.itemid=d.itemid
GROUP BY a.itemid
Analyze the counts for duplicate records, you can put a condition where count > 1 on every count.
I'm having difficulty figuring out how to create the proper syntax for my query.
Here is what i'm pulling. I have 2 tables.
Table 1 : Fields (user_id, name)
Table 2 : Fields (user_id, type, are_code, phone_number).
Table 1 can only have 1 record per user_id.
1 | John Doe
Table 2 can have up to 3 records per user_id:
1 | Home | 123 | 456.4567
1 | Work | 000 | 987.1467
1 | Mobi | 098 | 987.1756
How can i select everything so that my table will result in 1 record pulled like so :
user_id | name | home# | work# | mobi#
I tried this, which duplicates and doubles rows based on amount of entries within Table 2.
SELECT a.user_id,
b.area_code, b.phone_number
FROM users a
INNER JOIN user_contact_phones b ON a.user_id = b.user_id
That unfortunately returned 3 rows which is not good :(.
1 | John Doe | area | home# |
1 | John Doe | area | work# |
1 | John Doe | area | mobi# |
Any help and or pointers would be greatly appreciated.
Try this out:
SELECT
u.user_id,
u.name,
MAX(CASE WHEN p.type = 'Home' THEN phone_number END) HomeNumber,
MAX(CASE WHEN p.type = 'Work' THEN phone_number END) WorkNumber,
MAX(CASE WHEN p.type = 'Mobi' THEN phone_number END) MobiNumber
FROM phones p
JOIN users u ON p.user_id = u.user_id
GROUP BY u.user_id, u.name
Output:
| USER_ID | NAME | HOMENUMBER | WORKNUMBER | MOBINUMBER |
|---------|----------|------------|------------|------------|
| 1 | John Doe | 456.4567 | 987.1467 | 987.1756 |
Fiddle here.
Also note that you can remove u.name if u.user_id determines u.name... which is most likely the case as it seems to be a primary key. That would speed things up a little bit.
Note: This assumes that you cant have more than one same type for the same user (as it is in your example data, which only has one column for home, work and mobile.
Use user_contact_phones.type to get exact what you want, like-
SELECT a.user_id,
b.area_code, b.phone_number
FROM users a
INNER JOIN user_contact_phones b ON a.user_id = b.user_id where b.type='Home'
Here's a solution that will work:
select u.user_id, u.name,
thome.area_code as home_area_code, thome.phone_number as home_phone_number,
twork.area_code as work_area_code, twork.phone_number as work_phone_number,
tmobi.area_code as mobi_area_code, tmobi.phone_number as mobi_phone_number
from table1 u
left outer join table2 thome on u.user_id = thome.user_id and thome.type = 'Home'
left outer join table2 twork on u.user_id = twork.user_id and twork.type = 'Work'
left outer join table2 tmobi on u.user_id = tmobi.user_id and tmobi.type = 'Mobi'
Please note the use of left outer join instead of inner join in case the record for a particular type does not exist. You will get null values for those columns in your result set with left outer join. With inner join, you would not get a result for a user that did not have all three types. Good luck!
I have two tables, users and posts. I'm trying to write a single query that finds the latest post by a user, but I'm having trouble. Here's what I have so far.
select a.username, b.last_post from logins as a join (select login_id, entry as last_post from posts) as b where a.id = b.login_id
+-----------+---------------------+
| username | last_post |
+-----------+---------------------+
| something | 2013-10-08 22:12:00 |
| other | 2013-10-08 22:13:00 |
| test | 2013-10-08 22:13:03 |
| test | 2013-10-08 22:14:20 |
| hello | 2013-10-08 22:12:53 |
| hello | 2013-10-08 22:12:56 |
+-----------+----------+----------+
So right now last_post is simply the timestamp of the post it's pulling. How do I get a table that displays ONLY the last post from these users?
if you only need two column, you can directly use MAX()
SELECT a.username,
MAX(b.entry) last_post
FROM logins a
INNER JOIN posts b
ON a.id = b.login_id
GROUP BY a.username
otherwise, if you want to show all columns in all table, you can have subquery which separately gets the latest entry for every login_id
SELECT a.*, b.*
FROM logins a
INNER JOIN posts b
ON a.id = b.login_id
INNER JOIN
(
SELECT login_id, MAX(entry) entry
FROM posts
GROUP BY login_id
) c ON b.login_id = c.login_id AND
b.entry = c.entry
I have a sql query that pulls all types of data from 3 different tables that I now want to display in an array. I can get it to output all the data from the sql query, but I only want to display part of the array at a time based on if the value of the column in table is the same. Will try to demonstrate below.
My sql result looks like this:
Client | Order | Exc1 | Exc2 | Rest | Reps |
-------------------------------------------------------
Steve | 1A | this | That | This | that |
-------------------------------------------------------
Mike | 1A | this | That | This | that |
-------------------------------------------------------
Jax | 1A | this | That | This | that |
-------------------------------------------------------
Steve | 1B | this | That | This | that |
-------------------------------------------------------
Mike | 1B | this | That | This | that |
-------------------------------------------------------
Jax | 1B | this | That | This | that |
I want my array to output this on a page1
Steve | 1A | this | That | This | that |
-------------------------------------------------------
Mike | 1A | this | That | This | that |
-------------------------------------------------------
Jax | 1A | this | That | This | that |
And this on page 2 and so on. Each page will contain a list of all clients and only one order value per page. The order column value will vary for each user as they will be able to input there own text for the order field. Is this possible and if so how is the best way possible?
#Gordon Linoff here is my current query. I dont really understand what you wrote or more of how it would relate to my query. below id my current query. I did not finish outputting into array. I just have this as I was testing until I got the results I wanted.
function get_workout_class(){
$workout_class = array();
$workout_query = mysql_query("
SELECT *
FROM `movements`
LEFT JOIN `classes`
ON `movements`.`class_id` = `classes`.`class_id`
LEFT JOIN `clients`
ON `movements`.`class_id` = `clients`.`class_id`
WHERE `classes`.`class_id` = '$class_id' AND `user_id` = ".$_session['user_id']."
ORDER BY `movements`.`order`, `clients`.`first_name`
");
}
Here is a screen shot of my query result so you can see how I want them grouped. Pages to be split by different "order" values. The number of clients will vary from class to class.
http://custommovement.com/help/query.png
Here is my new query. The first part works just fine but the subquery is giving my problems. Its not pulling any results. #GordonLinoff
function get_workout_class($class_id){
$class_id = (int)$class_id;
$workout_class = array();
$workout_query = mysql_query("
WITH `workouts` as (
SELECT
`movements`.`movement_id`,
`movements`.`order`,
`movements`.`mv_00`,
`movements`.`mv_01`,
`movements`.`mv_02`,
`movements`.`mv_03`,
`movements`.`mv_04`,
`movements`.`rep_set_sec`,
`movements`.`rest`,
`classes`.`class_name`,
`clients`.`client_id`,
`clients`.`first_name`,
`clients`.`last_name`,
`clients`.`nickname`
FROM `movements`
LEFT JOIN `classes` ON `movements`.`class_id` = `classes`.`class_id`
LEFT JOIN `clients` ON `movements`.`class_id` = `clients`.`class_id`
WHERE `classes`.`class_id` = '$class_id'
)
SELECT `wo`.*
(SELECT COUNT(DISTINCT `order`) FROM `workouts` `wo2` WHERE `wo2`.`order` <= `wo`.`order`) as `pagenum`
FROM `workouts` `wo`
ORDER BY `pagenum`
");
echo mysql_num_rows($workout_query);
}
I think you can solve your problem by adding a page number to your query. Unfortunately, this is moderately painful in mysql, because you have to use a self join or correlated subquery.
Here is an example of how to do it with a correlated subquery:
select t.*,
(select count(distinct order) from t t2 where t2.order <= t.order) as pagenum
from t
order by pagenum
Based on your original query (but without putting it into a string):
with workouts as (
SELECT *
FROM `movements` LEFT JOIN
`classes`
ON `movements`.`class_id` = `classes`.`class_id` LEFT JOIN
`clients`
ON `movements`.`class_id` = `clients`.`class_id`
WHERE `classes`.`class_id` = '$class_id' AND `user_id` = ".$_session['user_id']."
)
select wo.*,
(select count(distinct order) from workouts wo2 where wo2.order <= wo.order) as pagenum
from workouts wo
order by pagenum
This will almost work . . . just one caveat. You can put the "SELECT *" into the with clause because you have multiple columns with the same name. Put in the columns you need.
I forget that mysql does not support the "with" statement. My apologies for the bad syntax. One work around is to use a view or temporary table. Otherwise, the query is a bit more complicated because the logic has to be repeated twice:
select wo.*,
(select count(distinct order)
from (SELECT *
FROM `movements` LEFT JOIN
`classes`
ON `movements`.`class_id` = `classes`.`class_id` LEFT JOIN
`clients`
ON `movements`.`class_id` = `clients`.`class_id`
WHERE `classes`.`class_id` = '$class_id' AND `user_id` = ".$_session['user_id']."
) wo2
where wo2.order <= wo.order
) as pagenum
from (SELECT *
FROM `movements` LEFT JOIN
`classes`
ON `movements`.`class_id` = `classes`.`class_id` LEFT JOIN
`clients`
ON `movements`.`class_id` = `clients`.`class_id`
WHERE `classes`.`class_id` = '$class_id' AND `user_id` = ".$_session['user_id']."
) wo
order by pagenum
try this. It uses subquery for the max value of the order.
SELECT a.*
FROM myTable a INNER JOIN
(
SELECT Client,
Max(`Order`) as MaxOrder
FROM myTable
GROUP BY Client
) c
ON a.Client = c.Client AND
a.`Order` = c.MaxOrder
or the simpliest if i'm not mistaken
SELECT *
FROM myTable
WHERE `Order` = '1B'