Pracowałem ostatnio nad skryptem galerii w jednym z projektów i w pewnym momencie natrafiłem na problem polegający na wyświetlaniu w widoku pojedynczego zdjęcia linków kierujących do następnego i poprzedniego elementu. Nie jest to pierwszy raz, kiedy zostałem zmuszony do “poradzenia sobie” z tego typu sytuacją, dlatego uznałem, że warto opisać wykorzystane rozwiązanie na blogu. Standardowo mam nadzieję, że się przyda, zatem zapraszam do lektury. ;]

Fotografia: ayesamson, CC-BY.

(My)SQL: Jak znaleźć poprzedni i następny rekord w jednym zapytaniu?

Załóżmy następującą sytuację: mamy tabelę zawierającą galerie:

CREATE TABLE IF NOT EXISTS `galleries` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) default NULL,
  `description` text,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

i drugą tabelę zawierającą zdjęcia:

CREATE TABLE IF NOT EXISTS `photos` (
  `id` int(11) NOT NULL auto_increment,
  `gallery` int(11) default NULL,
  `file` varchar(255) default NULL,
  `createdAt` datetime default NULL,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

Wybierając konkretne zdjęcie [id = 4]:

SELECT *
FROM photos
WHERE id = 4

dostajemy odpowiednie dane w tablicy pobranej z bazy danych. Chcąc wygenerować linki do poprzedniego i następnego zdjęcia musimy pobrać identyfikator “lewego” i “prawego” zdjęcia z tej samej galerii. Oto kod rozwiązania:

SELECT pp.*,
	(SELECT MAX(id) FROM photos p WHERE p.gallery = pp.gallery AND id < 4) AS `left`,
    	(SELECT MIN(id) FROM photos p WHERE p.gallery = pp.gallery AND id > 4) AS `right`
FROM photos pp
WHERE id = 4

Rozwiązanie polega na tym, że pobieramy podzapytaniem w pierwszym przypadku największy identyfikator spośród wszystkich mniejszych od danego, a w drugim najmniejszy spośród wszystkich większych od danego. Wszystko oczywiście w ramach jednej galerii.

Mam nadzieję, że dzisiejszy krótki wpis będzie służył Wam jako szybka referencja w razie potrzeby. Przy okazji - może podzielicie się własnymi sposobami na rozwiązanie tego problemu?