PHP/SQL creating links to next row in a database - php

Lets say i have a databse:
+----------+
| Database |
+----------+
| id |
| image |
| category |
+----------+
Now i have a page that shows an image from the database, i want to add a
<< Previous image
and
Next image >>
button. I could just take the $id and add +1 , but what if the next ID does not exist in the DB ?
Any help appreciated, thanks
So i found this:
SELECT *
FROM database AS c
WHERE (id = (SELECT MAX(id) FROM database WHERE id < c.id AND language = 'en')
OR id = (SELECT MIN(id) FROM database WHERE id > c.id AND language = 'en'))
But how do i make a link out of it, like:
Next ?

You'll have to use another select:
SELECT
( SELECT ID FROM <TABLE-NAME> WHERE ID > $currentID ORDER BY ID ASC LIMIT 1 )
AS NEXT_VALUE,
( SELECT ID FROM <TABLE-NAME> WHERE ID < $currentID ORDER BY ID ASC LIMIT 1 )
AS PREV_VALUE
FROM DUAL;

As explained in this answer, you can use a subselect query to get the ID of the previous and next records:
...
WHERE id IN (
'$id',
(SELECT MAX(id) FROM yourTable WHERE id < '$id'),
(SELECT MIN(id) FROM yourTable WHERE id > '$id')
)
...

Related

Get position of an ID based on MySQL COUNT result

I am not even sure if this has been answered because I don't even know how to coin the problem. But here is what am trying to do.
I am using COUNT() to create a tabular representation of a data from top to bottom for a 30 day period.
SELECT id FROM table WHERE col = '123' AND date >= DATE_SUB(CURRENT_DATE, INTERVAL DAYOFMONTH(CURRENT_DATE)-1 DAY) AND date <= LAST_DAY(CURRENT_DATE) GROUP BY id ORDER BY COUNT(id) DESC
And I get the result with the most at the top
id | col
==========
id3 | 123
id5 | 123
id2 | 123
id4 | 123
id8 | 123
id5 | 123
id1 | 123
id9 | 123
id7 | 123
This works fine for a tabular view and I can use ol to create a numbering system from 1 - 10. My issue is, I want to be able to tell the position of any given id. Eg. if I want to get the position of id9 in this count result i.e. 8, how do I do that?
If you are using MySQL v8.0 or higher you can use the RANK function:
SELECT COUNT(*), RANK() OVER (ORDER BY COUNT(id) DESC) AS r FROM table GROUP BY id ORDER BY COUNT(id) DESC;
For previous version of mysql, you need to create the variable your self:
SELECT COUNT(*), #rank := #rank + 1 AS r FROM table, (SELECT #rank := 0) temp ORDER BY COUNT(id) DESC;
Note SELECT #rank := 0 initiate the variable.
Updated:
To select a specific id and it's rank, you can use:
SELECT * FROM (
SELECT id, COUNT(*), RANK() OVER (ORDER BY COUNT(id) DESC) AS r FROM table GROUP BY id ORDER BY COUNT(id) DESC
) ranked WHERE id = ?;

MySQL Select one row per ID according to highest submitted date per ID

I have the table:
id | date_submitted
1 | 01/01/2017
1 | 01/02/2017
2 | 01/03/2017
2 | 01/04/2017
I'm looking for the correct SQL to select each row, limited to one row per id that has the latest value in date_submitted.
So the SQL should return for the above table:
id | date_submitted
1 | 01/02/2017
2 | 01/04/2017
The query needs to select everything in the row, too.
Thanks for your help.
You can find max date for each id in subquery and join it with the original table to get all the rows with all the columns (assuming there are more columns apart from id and date_submitted) like this:
select t.*
from your_table t
inner join (
select id, max(date_submitted) date_submitted
from your_table
group by id
) t2 on t.id = t2.id
and t.date_submitted = t2.date_submitted;
Note that this query will return multiple rows for an id in case there are multiple rows with date_submitted equals to max date_submitted for that id. If you really want only one row per id, then the solution will be a bit different.
If you just need id and max date use:
select id, max(date_submitted) date_submitted
from your_table
group by id

Updating a table based on a query of the same table

I have a table which stores information on standings in multiple leagues, think of this as a fantasy site. The structure is as follows in terms of columns.
league_id | user_id | total_points | prediction_difference | current_position | last_position
In order to calculate the current standings I am issuing the following query:
SELECT
*
FROM f_u_standings
WHERE league_id = 1
ORDER BY total_points DESC,
prediction_difference DESC
My question is, now I have this result set, how can I then perform an UPDATE based on the SELECT query which updates the current_position column? My programming language of choice on this project is PHP.
you can update with a select.. this assumes you have an ID for each row
UPDATE TABLE f_u_standings fs,
(
SELECT
*
----- do what you want to change current_position -----
FROM f_u_standings
WHERE league_id = 1
ORDER BY total_points DESC,
prediction_difference DESC
) temp
SET fs.current_position = temp.current_position WHERE fs.id = temp.id
This may be closer to what you need:
UPDATE f_u_standings fs,
(SELECT #rownum:=#rownum+1 rownum, id
FROM f_u_standings, (SELECT #rownum := 0) init
WHERE league_id = 1
ORDER BY total_points DESC,
prediction_difference DESC) temp
SET fs.current_position = temp.rownum
WHERE fs.id = temp.id

Count/Check first instances of entries in mysql table

id | user_id | date_tracked
---------------------------------------------
1001 | 1 | 10-10-2013
1002 | 2 | 10-10-2013
1003 | 3 | 10-10-2013
1004 | 1 | 10-11-2013
1005 | 2 | 10-12-2013
I have a table similar to this, which tracks a user and a date. I need to find how many first-time entries for users occurred on a selected date. This table is going to hold a significant amount of data, which is why I'd like to rely on a query to process this instead of a bunch of PHP loops.
i.e. on 10-11-2013, user 1 visited but not their first time, so return 0
on 10-10-2013, user 1 and 2 visited for their first time, so return 2.
Obviously, using a simple query can count the number of entries on a specified date, but what methodology will allow me to only count if the user_id is not present on a row prior.
The table is ordered by date, meaning that a more recent date should never have a smaller id than an older date.
Any ideas?? Thanks!
Finding all "first time"-date, by user:
SELECT user_id, MIN(date_tracked) AS first_date
FROM table
GROUP BY user_id
Counting "first time", for each date:
SELECT t.first_date, COUNT(*) AS nb
FROM (SELECT user_id, MIN(date_tracked) AS first_date
FROM table
GROUP BY user_id) t
GROUP BY t.first_date
In response to Filipe,
Maybe this would be more suitable?
SELECT COUNT(*)
FROM table t1
WHERE t1.date ='2013-8-27'
AND NOT EXISTS (
SELECT 1
FROM table t2
WHERE t2.user_id = t1.user_id
AND t2.id < t1.id
);
SELECT user_id, MIN(date_tracked)
FROM table_name
GROUP BY user_id
By your tags I assume you want your answer in php as well.
Just one query: shouldn't date 10-10-2013 return 3?
Anyway you can try this:
<?php
$dbConnect = #mysqli_connect($host, $user, $pass)or die();
#mysqli_select_db($dbConnect, $dbname) or die();
$query = "SELECT id FROM tablename WHERE date_tracked = '$searchDate' AND (SELECT COUNT(id) FROM tablename WHERE date_tracked < '$searchDate')=0";
$queryResult = #mysqli_query($dbConnect, $query) or die();
$rowCount = mysqli_num_rows($queryResult);
echo $rowCount . "<br/>";
mysqli_close($dbConnect);
?>
For counting as one, if the user visits multiple times in the first day, you can do it in two ways:
SELECT COUNT(distinct user_id)
FROM user t1
WHERE t1.date_tracked = '2013-10-12'
AND NOT EXISTS (
SELECT 1
FROM user t2
WHERE t2.user_id = t1.user_id
AND t2.date_tracked < t1.date_tracked
);
SELECT COUNT(user_id)
FROM user t1
WHERE t1.date_tracked ='2013-10-12'
AND NOT EXISTS (
SELECT 1
FROM user t2
WHERE t2.user_id = t1.user_id
AND t2.id < t1.id
);
I think i prefer the second, as it is much more cleaner by comparing ID's and not having to do the distinct.
sqlfiddle demo

Mysql replace two value in one query?

BEFORE
id | cat_id | order
33 | 1 | 1
34 | 1 | 2
AFTER
id | cat_id | order
33 | 1 | 2
34 | 1 | 1
Now using 4 query
$db is wrap $mysqli for using placeholder and injection defense
get first record by id
$curr = $db->q('SELECT id,order,cat_id FROM `tbl` WHERE id`=? FOR UPDATE',
33)->fetch_assoc();
if exist first record find next record by order field
if($curr){
$next = $db->q('SELECT id,order FROM `tbl` WHERE `cat_id`=? AND
`order`>? ORDER BY `order` LIMIT 1 FOR UPDATE',
$curr['cat_id'],$curr['order']));
if exist first and second recorn change order value
if($prev['id']){
$db->q("UPDATE `tbl` SET `order`=? WHERE `id`=?",$next['order'],$curr['id']);
$db->q("UPDATE `tbl` SET `order`=? WHERE `id`=?",$curr['order'],$next['id']);
}
}
Important! Checking exist two record, lock rows for update
MySQL doesn't support update with the same table in the FROM statement. So because of this there are (select * from TBL) as t2 in inner subqueries.
Also EXISTS condition in the first CASE WHEN is to prevent update if the second record doesn't exists ("if exist first and second records change order value")
Here is a SQLfiddle example
UPDATE tbl as t1
SET `order`=
CASE WHEN id = 33
and
EXISTS (SELECT ID from (select * from TBL) t2 where
cat_id=t1.Cat_Id
and `order`>t1.`order`
ORDER BY `order`
LIMIT 1)
THEN
(SELECT `order` from (select * from TBL) t2 where
cat_id=t1.Cat_Id
and `order`>t1.`order`
ORDER BY `order`
LIMIT 1)
WHEN id <>33 THEN
(SELECT `order` from (select * from TBL) t2 where
cat_id=t1.Cat_Id
and `order`<t1.`order`
ORDER BY `order` DESC
LIMIT 1 )
ELSE `order`
END
where id =33
or
(SELECT ID from (select * from TBL) t2 where
cat_id=t1.Cat_Id
and `order`<t1.`order`
ORDER BY `order` DESC
LIMIT 1) =33
With one query it's:
UPDATE
`tbl`
SET
`order`=CASE
WHEN `order`=2 THEN 1
WHEN `order`=1 THEN 2
END;
WHERE
`order` IN (1,2)
or, for id's condition:
UPDATE
`tbl`
SET
`order`=CASE
WHEN `order`=2 THEN 1
WHEN `order`=1 THEN 2
END;
WHERE
id = $id
To swap 2 fields by row id try:
UPDATE `tbl` AS tbl1
JOIN `tbl` AS tbl2 ON ( tbl1.id = 33 AND tbl2.id = 34 )
SET
tbl1.order = tbl2.order, tbl2.order = tbl1.order
Also you can set your desired value instead of swap between 2 fileds.
If needed, you can add a where clause like below to swap where cat_id are 1 in two rows:
WHERE
tbl1.cat_id = 1 AND tbl2.cat_id = 1
Update:
If your order numbers are unique for any cat_id you can try this way:
UPDATE `tbl` AS tbl1
JOIN `tbl` AS tbl2 ON ( tbl1.order = 1 AND tbl2.order = 2 )
SET
tbl1.order = tbl2.order, tbl2.order = tbl1.order
WHERE
tbl1.cat_id = 1 AND tbl2.cat_id = 1
It works if your order field is int, Otherwise you should quote order values in query.
See the result on SQLFiddle

Categories