Selecting users alphabetically based on a specific ID - php

I'm familiar with pagination, in that I can select a group of users based on a page number like so:
// setup pagination
$page = 1;
$display = 5;
$start = $display * $page - $display;
$sql = "SELECT * FROM users WHERE valid = 'Y' ORDER BY :username ASC LIMIT :start, :display";
$sth = $this->db->prepare($sql);
$sth->bindValue(':username', $username, PDO::PARAM_STR);
$sth->bindValue(':start', $start, PDO::PARAM_INT);
$sth->bindValue(':display', $display, PDO::PARAM_INT);
$sth->execute();
$result = $sth->fetchAll(PDO::FETCH_ASSOC);
What I'm trying to figure out is how to do something similar only instead of a page number I have a user id. For exmaple, given the user id "3" and a display limit of "3", I want to select that user along with the user immediately before and after alphabetically (for a total of three users). I hope that makes sense..
Any advice on how to approach this?

Here is an approach that uses three subqueries combined with union all:
(select *
from users
where valid = 'Y' and username < :username
order by username desc
limit 1
)
union all
(select *
from users
where valid = 'Y' and username = :username
order by username desc
limit 1
)
union all
(select *
from users
where valid = 'Y' and username > :username
order by username
limit 1
)

Here's one idea...
SELECT * FROM ints;
+---+
| i |
+---+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
+---+
(SELECT * FROM ints WHERE i >= 3 ORDER BY i LIMIT 2)
UNION
(SELECT * FROM ints WHERE i < 3 ORDER BY i DESC LIMIT 1)
ORDER BY i;
+---+
| i |
+---+
| 2 |
| 3 |
| 4 |
+---+

Related

SQL - Get multiple values when limit 1

If I have a table like this:
ID | ident | product
1 | cucu1 | 99867 |
2 | kkju7 | 88987 |
3 | sjdu4 | 66754 |
4 | kjhu6 | 76654 |
5 | cucu1 | 98876 |
And use this query: SELECT ident,COUNT(*) FROM sales WHERE status=? AND team=? AND DATE(date) = DATE(NOW() - INTERVAL 1 DAY) GROUP BY ident order by COUNT(*) DESC LIMIT 1
I get the value: cucu1, since that has the most rows.
But if my table is like this:
ID | ident | product
1 | cucu1 | 99867 |
2 | kkju7 | 88987 |
3 | sjdu4 | 66754 |
4 | kkju7 | 76654 |
5 | cucu1 | 98876 |
It should return both cucu1 and kkju7, since they are the highest with same count, but still it gives me only cucu1. What am I doing wrong?
You can use rank():
SELECT ident, cnt
FROM (SELECT ident, COUNT(*) as cnt,
RANK() OVER (ORDER BY COUNT(*) DESC) as seqnum
FROM sales
WHERE status = ? AND team = ? AND
DATE(date) = DATE(NOW() - INTERVAL 1 DAY)
GROUP BY ident
) i
WHERE seqnum = 1;
LIMIT keyword simply limits the results to 1 row, no matter if there are equal values before or after the returned row.
A better solution would be to select the rows which have a count that's equal to max count in the query, which can be achieved by the following query:
SELECT ident,COUNT(*)
FROM sales
WHERE status=?
AND team=?
AND DATE(date) = DATE(NOW() - INTERVAL 1 DAY)
GROUP BY ident
HAVING COUNT(*) = MAX(COUNT(*))

How can I UPDATE the result of a SELECT statement?

I have a table like this:
// notifications
+----+--------------+------+---------+------------+
| id | event | seen | id_user | time_stamp |
+----+--------------+------+---------+------------+
| 1 | vote | 1 | 123 | 1464174617 |
| 2 | comment | 1 | 456 | 1464174664 |
| 3 | vote | 1 | 123 | 1464174725 |
| 4 | answer | 1 | 123 | 1464174813 |
| 5 | comment | NULL | 456 | 1464174928 |
| 6 | comment | 1 | 123 | 1464175114 |
| 7 | vote | NULL | 456 | 1464175317 |
| 8 | answer | NULL | 123 | 1464175279 |
| 9 | vote | NULL | 123 | 1464176618 |
+----+--------------+------+---------+------------+
And here is my query:
(SELECT id, event, seen, time_stamp
FROM notifications n
WHERE id_user = :id AND seen IS NULL
)UNION
(SELECT id, event, seen, time_stamp
FROM notification n
WHERE id_user = :id AND seen IS NOT NULL
LIMIT 2
)UNION
(SELECT id, event, seen, time_stamp
FROM notifications n
WHERE id_user = :id
ORDER BY (seen IS NULL) desc, time_stamp desc
LIMIT 15
)
ORDER BY (seen IS NULL) desc, time_stamp desc;
Now I'm trying to update matched rows from query above and set seen = 1, Something like this:
UPDATE notifications SET seen = 1 WHERE /* the result of query above */
How can I do that?
Note: I also use PHP and PDO to execute that SELECT query (If it is important to know)
$stm = $db->prepare(" (SELECT id, ... ");
$stm->execute( /* passing some variables */);
$stm->fetchAll(PDO::FETCH_ASSOC);
seen can only be 1 or null. In that case, most of what you are getting from that UNION query is irrelevant. It seems to me that the end result of the update you're trying to do will be:
UPDATE notifications SET seen = 1 WHERE id_user = :id AND seen IS NULL
Anything else will be updating something that's already 1 to 1.
I think you can use where in clause .. but in this case you need ond the id
UPDATE notifications SET seen = 1 WHERE id in (
(SELECT id
FROM notifications n
WHERE id_user = :id AND seen IS NULL
)UNION
(SELECT id
FROM notification n
WHERE id_user = :id AND seen IS NOT NULL
LIMIT 2
)UNION
(SELECT id
FROM notifications n
WHERE id_user = :id
ORDER BY (seen IS NULL) desc, time_stamp desc
LIMIT 15
))
If you want to do this in MySQL, use JOIN:
update notifications n join
(select id
from ((SELECT id, event, seen, time_stamp
FROM notifications n
WHERE id_user = :id AND seen IS NULL
) UNION
(SELECT id, event, seen, time_stamp
FROM notification n
WHERE id_user = :id AND seen IS NOT NULL
LIMIT 2
) UNION
(SELECT id, event, seen, time_stamp
FROM notifications n
WHERE id_user = :id
ORDER BY (seen IS NULL) desc, time_stamp desc
LIMIT 15
)) n
) nids
on n.id = nids.id
set seen = 1;
You can slightly modify your query to use as subquery for update statement:
UPDATE notifications SET seen = 1 WHERE id in (
(SELECT id
FROM notifications n
WHERE id_user = :id AND seen IS NULL
)UNION
(SELECT id
FROM notification n
WHERE id_user = :id AND seen IS NOT NULL
LIMIT 2
)UNION
(SELECT id
FROM notifications n
WHERE id_user = :id
ORDER BY (seen IS NULL) desc, time_stamp desc
LIMIT 15
)
)
I assume you have retrieved all applicable ID's into your application. All you need to do is then is
UPDATE notifications
SET seen = 1
WHERE id IN (?,?,?)
where the ? are replaced by the id values.

Mysql SELECT different

I have a question.
My database table is something like this:
| ID | Name | Value | param |
| 1 | Michael | 290 | X |
| 2 | John | 300 | X |
| 3 | Michael | 270 | X |
| 4 | John | 280 | X |
| 5 | Michael | 256 | Y |
| 6 | Michael | 230 | Y |
¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨
So, I want to use a form to select the latest rows with different param but equal name.
For example, if I search for "Michael", I want to use PHP to show the latest value for the param X and the latest value for the param Y (returning 2 rows).
Michael: Param Y: 230
Michael: Param X: 270
And if I search for "John" I get:
John: Param X: 280.
The code
$sql = "SELECT * FROM thetable WHERE name = 'Michael' ORDER BY ID DESC";
$result = mysql_query($sql);
Now I just want for it to select only the latest rows with different param.
Thanks in advance.
Are the approaches listed won't work with n variable "params". I think something similar may work:
SELECT
t.*
FROM Table1 t
JOIN
(SELECT
max(id) AS maxid
FROM Table1
GROUP BY name,param) x
on x.maxid = t.id
WHERE name='Michael'
See http://sqlfiddle.com/#!2/64dc4/11
Use UNION
SELECT * From table WHERE name='Michael' AND PARAM='X' ORDER BY ID DESC LIMIT 1
UNION
SELECT * From table WHERE name='Michael' AND PARAM='Y' ORDER BY ID DESC LIMIT 1
use LIMIT if you want to select just one row ( hope i understood the question )
$sql = "SELECT * FROM thetable WHERE name = 'Michael' AND param = 'x' ORDER BY Value DESC LIMIT 1
UNION
SELECT * FROM thetable WHERE name = 'Michael' AND param = 'y' ORDER BY Value DESC LIMIT 1"

MySQL: How to show records after a specific ID

+----+
| id |
+----+
| 1 |
+----+
| 2 |
+----+
| 3 |
+----+
| 4 |
+----+
+----+
| 5 |
+----+
How do I show records from a specific ID so the list would show 2,3,4,5 or 3,4,5?
I figured to do with two queries in UNION but end up showing 2,1,3,4,5 or 2,5,4,3,1.
Did you mean
SELECT * FROM table WHERE id IN (2,3,4,5)
SELECT * FROM table WHERE id >= $id ORDER BY id ASC LIMIT 4
In the second query $id is the input from the user. Also instead of LIMIT 4, you can have the 4 taken as user input
Maybe
$sql = "SELECT * FROM table WHERE id >= $curID ORDER BY id ASC LIMIT 4";
If you want to specify how many entries to find, you can use:
$sql = "SELECT * FROM table WHERE id >= $curID ORDER BY id ASC LIMIT $number";
Be sure you sanitize the inputs before plugging them into the query. See this post for more info:
What's the best method for sanitizing user input with PHP?

Find Max Value In Database Column With Where Clause

Lets say I have the database table setup in this fashion,
ID | Name | Area | Timestamp
---+-------+------+------------
1 | Hill | 1 | 1293243080
2 | Sam | 1 | 1293243084
3 | Joe | 2 | 1293243087
4 | Bob | 2 | 1293243089
5 | Matt | 3 | 1293243091
6 | Billy | 3 | 1293243095
Then I wish to return the Name of the person with the largest Timestamp and with a certain Area number.
However, when I try to return for example the Name Bob I only get Billy because he has the largest Timestamp of everyone.
How can I get the php to select not only the person with the max Timestamp, but the person with a certain Area number also?
This is my code so far -
(I am looping it because I am displaying the name of the person with the largest Timestamp in each Area)
for ($t = 1; $t <= 3; $t++){
$result = mysql_query("SELECT * FROM forum_posts WHERE Area='$t' AND Timestamp=(select max(Timestamp) from forum_posts)");
while($row = mysql_fetch_array($result))
{
$post_name[$t]=$row['Name'];
}
}
print_r ($post_name);
What do you guys suggest I do?
$result = mysql_query("SELECT * FROM forum_posts WHERE Area='$t' AND Timestamp=(select max(Timestamp) from forum_posts where Area='$t')");
a better option would be.
$result = mysql_query("SELECT * FROM forum_posts WHERE Area='$t' ORDER BY Timestamp DESC LIMIT 1");
use this
$result = mysql_query("SELECT * FROM forum_posts WHERE Area='$t' ORDER BY Timestamp DESC LIMIT 1");
You need a GROUP BY on your query.
You need a OR Condition. The query would be:
$result = mysql_query("SELECT * FROM forum_posts WHERE Area='$t' OR Timestamp=(select max(Timestamp) from forum_posts)");
SELECT * FROM forum_posts (
SELECT
RANK() OVER (ORDER BY timestamp ASC) AS ranking,
name
FROM person
WHERE area = 1
) AS foo
WHERE ranking = 1

Categories