Re: Building an index for next/last in a photo album.
by waswas-fng (Curate) on Jul 26, 2004 at 20:15 UTC
|
If the next and previous are just -- and ++ the id on the current image, you can do (in psudo sql) select images from the database where the image ID is greater than or equal to ($id - 1) and image ID is less than or equal to ($id +1) ordered by id . then you just need to special case the times where the database returns < 3 results (top and bottom of the stack).
| [reply] |
|
I had considered that, but the problem is that the img_id's are sequential in the database -- not the album. In other words, if I wanted img_id #43, I could not just say "give me img_id #42, #43 and #44" - because #42 and #44 could possibly belong to another album_id for the same user - or another album_id for a completely different user.
Here is an example of the table:
img_id | album_id | uid | name | ext
-------+----------+-----+--------------+------
38 | 14 | 89 | mypetrat | jpg
39 | 14 | 89 | mypetlemur | jpg
40 | 2 | 12 | vacation_01 | jpg
41 | 14 | 89 | mypetvulture | jpg
42 | 2 | 12 | vacation_02 | jpg
43 | 2 | 12 | vacation_03 | jpg
44 | 14 | 89 | mypetcow | jpg
| [reply] [d/l] |
|
What database? if Mysql you should be able to use a more generic query that limits to the user and album and then use it's INDEX statement to say only the Item N -> N+2.
| [reply] |
Re: Building an index for next/last in a photo album.
by Roy Johnson (Monsignor) on Jul 26, 2004 at 20:44 UTC
|
I can't figure out how to pull the target record, plus the one before and after it in a single SQL query. I suppose that can't be done.
It can be done, though it's not particularly efficient, and the exact syntax of the query will depend on which database you're using. The strategy is to outer join the table to itself twice (once for the prev, once for the next). Something like (in Oracle):
select max(P.img_id), T.img_id, min(N.img_id)
from images T, images P, images N
where P.img_id(+) < T.img_id and P.uid(+) = T.uid and P.album_id(+) =
+ T.album_id
and N.img_id(+) > T.img_id and N.uid(+) = T.uid and N.album_id(+) =
+ T.album_id
and T.img_id = ? and T.uid = ? and T.album_id = ?
group by T.img_id
That said, grabbing the array is a better way to do it.
Update: added other outer-joined columns.
We're not really tightening our belts, it just feels that way because we're getting fatter.
| [reply] [d/l] |
Re: Building an index for next/last in a photo album.
by davidj (Priest) on Jul 26, 2004 at 20:34 UTC
|
Sounds rather complicated to me. If it's not too much of a hassle, I would suggest that you redesign your database to use img_id as the primary key (assuming that it is unique). You could then easily calculate the before and after img_id values and select them from the database in 1 SQL query. (It would also be very quick since primary keys are indexed)
my ($img_id) = $str =~ m/img_id=(\d+)/;
my $prev_id = $img_id - 1;
my $next_id = $img_id + 1;
Then the SQL query (something like):
"select WHATEVER from TABLE where img_id in ($prev_id, $img_id, $next_
+id)"
Hope this helps,
davidj | [reply] [d/l] [select] |
|
The problem is that this application will serve infinite users with infinite albums, so while img_id is unique and sequential, it doesn't gaurantee that any two images belong to the same person or album.
| [reply] |
|
Ok, this may or may not be a good solution, depending you whether or not you want to mess with your database design, but it will work.
Somewhere in the table put another column for a sequence number. So, instead of
img_id | album_id | uid | name | ext
-------+----------+-----+--------------+------
38 | 14 | 89 | mypetrat | jpg
39 | 14 | 89 | mypetlemur | jpg
40 | 2 | 12 | vacation_01 | jpg
41 | 14 | 89 | mypetvulture | jpg
42 | 2 | 12 | vacation_02 | jpg
43 | 2 | 12 | vacation_03 | jpg
44 | 14 | 89 | mypetcow | jpg
you have something like
img_id | album_id | seq_id | uid | name | ext
-------+----------+--------+-----+--------------+------
38 | 14 | 1 | 89 | mypetrat | jpg
39 | 14 | 2 | 89 | mypetlemur | jpg
40 | 2 | 1 | 12 | vacation_01 | jpg
41 | 14 | 3 | 89 | mypetvulture | jpg
42 | 2 | 2 | 12 | vacation_02 | jpg
43 | 2 | 3 | 12 | vacation_03 | jpg
44 | 14 | 4 | 89 | mypetcow | jpg
You could then grab the seq_id to the corresponding img_id
select seq_id from TABLE where img_id = $img_id
Then 1) calculate prev and next seq_id and 2) grab the img_ids you want be referencing the seq_id
my $p_seq_id = $seq_id - 1;
my $n_seq_id = $seq_id + 1;
"select img_id from TABLE where seq_id in ($p_seq_id, $seq_id, $n_seq_
+id)"
You could easily keep the current album seq_id value in another table and reference it when adding new images. As I said, it may be a hassle modifying your database, but it may be worthwhile in the long run as it more easily does what you want than the other options.
Note: This may be a good "teachable moment" as educators like to call them.
Perhaps the most important thing in designing an application that uses a database is to know thoroughly what you want from the application before you even begin designing the database. Too often, people design a database based on a less than thorough examination of the application requirements and end up having to redo it (the database.) :)
davidj | [reply] [d/l] [select] |
Solution - Re: Building an index for next/last in a photo album.
by Seumas (Curate) on Jul 27, 2004 at 07:14 UTC
|
This is the solution I put together. I'm not sure how speedy it is in relation to the other suggestions in this thread, but as long as no album has more than a few thousand images, I suspect this method should be the fastest solution.
If anyone has further ideas to tighten this up or yet other alternative approaches, I'm eager for you to share them with me.
# Elsewhere in the code, we get an img_id, do a SELECT to find what
# album_id it belongs to, then use the SELECT below to get all of
# the img_id's that belong to that album. We use flattenArray() to
# turn the arrayref from DBI into a plain old array.
my @image_idx = flattenArray( @{$dbh->selectall_arrayref("SELECT img_i
+d FROM images WHERE album_id = $image_id")});
# Find what place our target img_id is in the array.
my $idx_loc = indexArray($img_id, @image_idx);
# Get img_id's from array that come before and after the target.
my $prev_img = $image_idx[$idx_loc - 1];
my $next_img = $image_idx[$idx_loc + 1];
# Thanks to merlyn, tilly and particle
# http://perlmonks.org/index.pl?node_id=151120
sub flattenArray {
my @flattened; # Will be in reverse order
while (@_) {
my $last = pop;
if (UNIVERSAL::isa($last, "ARRAY")) { push @_, @$last; }
else { push @flattened, $last; }
}
return reverse @flattened;
}
# My apologies, but I took this from a golf thread on PM. I've lost
# the node number and apologize to the author. Please let me know
# so I can credit you for this.
sub indexArray(@) {
my $s=shift;
$_ eq $s && return @_ while $_=pop;
-1;
}
| [reply] [d/l] |
|
| [reply] |
Re: Building an index for next/last in a photo album.
by ccn (Vicar) on Jul 26, 2004 at 20:24 UTC
|
what would be the quickest/shortest way to turn the $album_idx = $dbh->selectall_arrayref() into just an array?
@album_idx = @{$dbh->selectall_arrayref()}
Update: also, you may put album_id in the url, and eliminate the first SQL query
| [reply] [d/l] [select] |