I am trying to make a photo gallery in php + mysql.
The URL viewphoto.php?id=143 shows photo 143.
In the navigation menu, I want to display the previous two photos in that album, and the next two.
I thought of using:
$temp_id = $id - 2;
mysql_query("SELECT id, photo FROM photos WHERE album = {$album} AND id >= {$temp_id} LIMIT 5");
But that didn't work, because photo's from different albums could have the ids preceding and succeeding the one of the viewed photo.
Does anyone know how I could do this?
Thanks.
Using the id to sort your pictures is a bad idea. Imagine you delete one picture. Your chain of pictures will be broken. In order to fix it, you would need to change the id column, which is an even worse idea.
Either use a seperate index column for the sorting within one album. This index could be rebuilt easily in the case of a picture getting deleted.
Or you define a "previous" and "next" column in your table. This would then contain the id of the last and next picture. If a picture gets deleted, you only need to change these columns for the previous and the next picture.
With both methods, you could for example use a nested self join to access your previous and next 2 pictures. Comment on this post if you need help on that.
I've been dealing with this issue myself and I never found an elegant solution to the problem, I ended up doing it in two queries:
// next
mysql_query("SELECT id, photo FROM photos WHERE album = {$album} AND id > {$id} ORDER BY id ASC LIMIT 2");
// prev
mysql_query("SELECT id, photo FROM photos WHERE album = {$album} AND id <= {$id} ORDER BY id DESC LIMIT 3");
Now the first item in "prev" once fetched would be the current photo.
This solution does has to be amended with a check that the first item in "prev" is in fact the requested id, because it doesn't make sure it's the proper id, in case of gaps in the series.
Related
Seems to be a simple question for someone who knows well SQL, but not for me.
Anyhow, here is a sample table:
Primary (and only) key is on id. So basically the scenario is as fallows. User may add images. Newly added images are inserted with comune_number value 0 avoiding duplicates (on file name = image via PHP). Images inserted can be assigned to a category from another table. The same image can be assigned to many categories, for each is inserted a new row with the category id (comune_number). Relation between the two tables is on comune_number.
I would like to show the images, with a checkbox checked for which is assigned already.
My question is simple. How to include all images once, but where the same image is already assigned, include that comune_number instead of 0. I don't care about the order. The result I would like to achieve is something like this:
I'm aware of GROUP BY, so if I try
mysql_query("SELECT * FROM banner WHERE `comune_number` = 0");
or
mysql_query("SELECT * FROM banner GROUP BY `image`");
I end up with the same (not wanted) result.
Most likely I have to combine two queries in one, but I can't figure out which and how.
Note1: I have tried many combinations in phpMyAdmin, based on my (little) knowledge and on what I found with Google (including Stackoverflow), but none of them resulted as shown.
Note2: MySQL version 5.1
Either MYSQL only or combined with PHP solutions are welcome.
EDIT
I need to keep the comune_number. So when I show the images, I need to know the id.
My queries must rely on comune_number, so when I need comune_number = 10, the result should be as on second image above.
EDIT2
It seems I wasn't made myself clear. So what I want, when user is watching category of id 10, show him all the images once, and mark the ones which were assigned to that category.
Another example is here. So if user is watching category (comune_number) of id=9, show every picture once, and mark the two assigned to it.
Based on your SQLFiddle and all the comments here is the updated query:
SELECT r.*
FROM (SELECT b.*
FROM banner b
WHERE b.comune_number = 9
UNION ALL
SELECT b2.*
FROM banner b2
WHERE b2.comune_number = 0
GROUP BY b2.image) r
GROUP BY r.image;
Live DEMO.
select * from
(SELECT * FROM banner order by
FIELD(comune_number,10,0))
abc group by `image`;
fiddle
Updated:
Query with filter condition:
select * from
(SELECT * FROM banner
where comune_number in (10,0) order by
FIELD(comune_number,10,0))
abc group by `image`;
an important tip. When you use GROUP BY all the field you put in your field list, must be in GRUOP BY clause or must be into an aggragate function. MySql has a strange behaviour, don't sign the error but if you try in another DBMS your query:
SELECT * FROM banner GROUP BY image
You have an error.
MySql applies for fields not present in group by an implicit limit 1.
Solution about your issue:
SELECT * FROM banner b1
WHERE b1.comune_number <= 'YOUR_CATEGORY'
AND NOT EXISTS
(SELECT 'X' FROM banner b2
where b2.image = b1.image
and b2.comune_number > b1.comune_number
AND b2.comune_number <= 'YOUR_CATEGORY')
EDIT
I've changed query, now I put a condition about input category. Where you find YOUR_CATEGORY put the value of category you see (i.e. 9).
I am not sure whether this is the exactly you need, but I think it can be helpful.Try this:
Select if(comune_number = 10, comune_number,0), id, image from table
You may change comune_number as per your convenience. Further nesting in IF condition is also possible.
I have 2 tables: tbImages, tbUsers
tbImages has lots of paths of images with unique ids
tbUsers has lots of users with unique ids...
I will code a page that make a delivery of images...This page will show all images ordering by id... The admin will select 7 images to send it to some user by email... I will have to register when and how many times some user has received that image (a 3rd table maybe)...
Here is the problem... I'll have to ORDER images by date of register.. Images already sent have to appear at end of that delivery page...
What is the better way to do this? tbImages has lots of columns one for each user? A 3rd table (tbDelivered) one row each user with column 'images received'? ?How to make this SELECT to show already sent images at end?
A 3rd table relating your imageID to a userID (relational table). Then you can use JOIN statements in your query. For example:
relational_table
imageID
userID
sendCount
Query could be:
SELECT sendCount
FROM relational_table
WHERE imageID = $imageID
AND userID = $userID
That would give you back the number of times that image has been sent to that user.
You will have to create a 3rd table that will contain:
The image ID
The user ID
The quantity
And you will make a select statement that will look like this:
SELECT tbImages.imageID, tbDelivered.quantity
FROM tbImages, tbDelivered
WHERE tbImages.imageID = tbDelivered.imageID;
To show the ones that have not already been delivered you will have to add at the end of it:
AND quantity = 0;
I hope this helps
I have searched everywhere but could not get anything. The scenario is that when I run a select statement from MySQL/PHP, I want to use Next & Previous buttons to navigate backwards and forward through the results.
Does anyone know how I can accomplish this?
Here's how I run the query: select everything from members where hair = black;
This returns 8 results, and I have a page like so details.php?id=3 which takes id and display the details.
I want to be able to keep clicking the next button and move to another id from the result.
How do I accomplish this?
Thank you for your assistance.
If you mean to display 1 product details per page with Next buttons, then
1) Get the total rows from table
2) Find total number of pages like
$totalPages = $totalRows; //since 1 record per page
3) Loop thru $totalPages value to generate next links
4) Get the id of product from page url $_GET
5) Query sql using te product id obtained frm GET
Well thats the basics, hope your get it
Assuming you have all ids in the $allIds var, try something like this:
<?php
$id = (int) $_GET['id'];
$key = array_search($id, $allIds);
$nextId = $allIds[$key+1];
?>
Well, you have 2 different scopes here to address, first, when you query you are in PHP/Server side mode. PHP gets some data, processes it, shows some of it to the knowledge i have of your problem and then sends it to the browser.
Next, you have the client scope, where the client has the HTML rendered to his screen and has the possibility to click NEXT and PREVIOUS. When he does that, he issues a request to the server to get the NEXT or PREVIOUS record based on the current one.
You have 2 scenarios to work this problem out:
1) Load the whole data into memory and scan it to find your current position, see if there is a NEXT and PREVIOUS element and respond to the request of the user. If the user asked for the NEXT, easy, just move one more record. If the user asked for PREVIOUS item, then when scanning using a WHILE or FOR/FOREACH, always keep in memory the "lastitem" you saw, you can use this "lastitem" as your PREVIOUS item.
2) In the event you have many (i mean like more than 1000) items, you need to use a little subquery magic and work this out using SQL.
select everything from members where hair = black AND id = XYZ ORDER BY id LIMIT 2;
This will return you the CURRENT AND NEXT elements. Then call the same query again but this time, order it DESC so that your 2 items are the CURRENT AND PREVIOUS.
select everything from members where hair = black AND id = XYZ ORDER BY id DESC LIMIT 2;
Note that you can order this the way you want, the goal is to get a static result, something that always gets out the same way so that you can reverse it and get the items around the selected one.
I hope this helps you
I've set up a simple gallery system in PHP that is built to display one image per page. My URL parameter simply uses a gallery variable and a page variable and does not use the image iD in any way to pull the image. This is because I'm setting my htaccess settings to make a friendly URL:
http://mysite.com/images/1/
^ Would pull the first image in my MySQL query
or
http//mysite.com/images/12/
^ Would pull the 12th image in my MySQL query
The PHP page would then look like:
images.php?gallery=images&page=1
and
images.php?gallery=images&page=12
The queries (simplified) would then look like this for each of the above:
For the first image:
SELECT id, img_src
FROM pictures
WHERE gallery = images
ORDER BY date_added DESC
LIMIT 0, 1
and for the 12th image:
SELECT id, img_src
FROM pictures
WHERE gallery = images
ORDER BY date_added DESC
LIMIT 11, 1
It's been working great but I ran into a problem now that I want to add a feature. I was hoping to display thumbnails of the ten most recently added images to the database no matter which gallery they belong to… i.e. this query:
SELECT id, gallery, img_src
FROM pictures
ORDER BY date_added DESC
LIMIT 10
Is there any way I can know which 'position' or 'page' each image would be for the specific gallery so that I can create the link correctly?
For example, say the ten most recent thumbnails return 4 pictures from the gallery 'images', then 2 pictures from the gallery 'weddings', then 3 pictures from the gallery 'portraits' and then one more image from the gallery 'images', so my links should then be:
http://mysite.com/images/1/
http://mysite.com/images/2/
http://mysite.com/images/3/
http://mysite.com/images/4/
http://mysite.com/weddings/1/
http://mysite.com/weddings/2/
http://mysite.com/portraits/1/
http://mysite.com/portraits/2/
http://mysite.com/portraits/3/
http://mysite.com/images/5/
Thanks for any help. I'm sure I'm overlooking something stupid easy here but I'm hoping to do it most efficiently as far as programming goes. So far my thoughts are that when I'm looping through the output I have to somehow retain each gallery's 'image count' and add one to this count each time an image of that gallery is added.
If you're still building the site I would change the URL's to show the actual image ID's and not a pseudo ID based on pagination.
This is good for several reasons:
SEO. You're pages stay the same. Google indexes them and when a visitor comes to the site at example.com/wedding/4234 he will actually find what he's looking for and not what Google indexed last time your site was scanned
Simplicity. You're already facing a problem that would be very easilly resolved if you were using real image ID's on the first place.
Analytics. You'll know what content is driving people to your site. There is no guessing here. URL's will remain the same always (no matter if new content comes in or not).
Quick and dirty:
$sql = "SELECT id, gallery, img_src
FROM pictures
ORDER BY date_added DESC
LIMIT 10";
$result = mysql_query($sql);
while($row = mysql_fetch_assoc($result)) {
if(!$$row['gallery']) $$row['gallery'] = array();
array_push($$row['gallery'], $row['id']);
$pagenumber = count($$row['gallery']);
echo "<a href=\"http://mysite.com/{$row['gallery']}/$pagenumber/\">
<img src=\"{$row['img_src']}\" alt=\"\"></a><br>";
// alt attribute for w3 validation (http://validator.w3.org/)
}
Edit:
Fixed code error. Now will dynamically create the array if it doesn't already exist.
(Originally, it illegally used the [ ] operator.)
I'm going to add to Frankie's answer, because I also believe the OP's current method is going to bite him the butt again one day. The OP may not find this useful, but it could help someone else.
You can use http://site.com/images/20, but the 20 represents an image ID instead of a page number. Of course the query to get the image is simple:
SELECT id, img_src
FROM pictures
WHERE gallery = images
AND id = 20
LIMIT 1
As a benefit this query is more efficient than using an offset with the LIMIT clause. But the OP said in a comment that he likes his current system because it doesn't require additional database queries to help build pagination links. Well, that's not a problem here.
Lets say you're on the page http://site.com/images/20. Your page links would be the following:
Prev - http://site.com/images/prev/20
Next - http://site.com/images/next/20
Obviously it didn't take any additional queries to build those links. They're just a slightly different URL showing the same image ID. But how do they work to move to the next or prev image? Simple. Instead of the above query, you would use one of these:
If the prev link was clicked, you use this query:
SELECT id, img_src
FROM pictures
WHERE gallery = 'images'
AND id < 20
ORDER BY id DESC
LIMIT 1;
If the next link was clicked, you use this query:
SELECT id, img_src
FROM pictures
WHERE gallery = 'images'
AND id > 20
ORDER BY id ASC
LIMIT 1;
The first query gives the image that came before the current one, and the second query gives the image that comes after the current one.
I have a database containing 40 pictures. These pictures are displayed using a pager.
I have a URL query: http://www.test.com/photo.php?id=15. This sets the current picture ID to 15. This picture is the 5th one on page 2.
How can I get the page a picture is on given only the ID?
SQL
select * from photo limit 40
PHP
$i=1;
while($r){
if($r[id]=$id) $cur_picRank = $i;
$i++;
}
$curPage = ceil( $cur_picRank / $pagesize);
Is this correct?
Easy-peasy.
You just have to count pictures shown before.
if them ordered by id, just SELECT count(*) where id < $id
So, you will get a position and now can divide it by page size.
For the different ordering you have to get field value first (e.g. to order by name get a name by id and then use it in condition)
As for your approach, it is NOT correct.
Selecting whole table to get just ONE row is always BAD idea.
Though this code would not work anyway. There is no loop exit condition and a counter doesn't count