KategorieBazy danych

[MySQL] Jak pobrać wybrany rekord oraz trzy następne i trzy poprzednie, tak aby wybrany był w środku wyników ?

Często na stronach możemy spotkać się z różnymi typami nawigacji, jednym z ciekawszych jest pokazywanie użytkownikowi kilka poprzednich i następnych rekordów co ma na celu zachęcić go do pozostania na stronie i przejrzenia kolejnych np. produktów w sklepie.

Zadanie to można zrealizować w prosty sposób wykorzystują łączenie wyników kilku zapytań ([b]UNION[/b]). Podstawowym warunkiem dla tego typu połączenia jest konieczność określenia takiej samej ilości kolumn, ale u nas nie będzie to problemem gdyż będziemy pracowali tylko na jednej tabeli.

Przykładowa tabela z danymi wygląda następująco:

+------+--------------+
| ID   | Nazwa        |
+------+--------------+
| 1    | Afganistan   |
+------+--------------+
| 2    | Albania      |
+------+--------------+
| 3    | Algieria     |
+------+--------------+
| 4    | Andora       |
+------+--------------+
| 5    | Angola       |
+------+--------------+
| 6    | Argentyna    |
+------+--------------+
| 7    | Armenia      |
+------+--------------+
| 8    | Australia    |
+------+--------------+
| 9    | Austria      |
+------+--------------+
| 10   | Bahamy       |
+------+--------------+

Poniżej kod potrzebny do utworzenia tabeli.

CREATE TABLE `panstwa` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
    `nazwa` VARCHAR( 200 ) NOT NULL
) ENGINE = MYISAM ;

Tabelę wypełniamy danymi.

INSERT INTO `panstwa` 
    (`id`, `nazwa`) 
VALUES 
    ('1', 'Afganistan'), 
    ('2', 'Albania'), 
    ('3', 'Algieria'), 
    ('4', 'Andora'), 
    ('5', 'Angola'), 
    ('6', 'Argentyna'), 
    ('7', 'Armenia'), 
    ('8', 'Australia'), 
    ('9', 'Austria'), 
    ('10', 'Bahamy');

Mając już środowisko testowe możemy przejść do tworzenia zapytania, które zwróci nam pożądane dane. Aby wybrać z tabeli państwo które nas interesuje użyjemy zapytania które nikogo nie zaskoczy:

SELECT * FROM panstwa WHERE nazwa = 'Angola'

W ten sposób otrzymaliśmy cały wiersz z informacjami o Angoli, teraz chcieli byśmy pobrać trzy kraje znajdujące się nad Angolą. Jako że mysql potrafi porównywać ciągi znaków oraz porządkować je w kolejności alfabetycznej więc kolejne zapytanie musi posortować tabelę według nazwy malejąco (dzięki czemu będziemy mieli od samej góry państwa najbliższe Angoli) i wybrać państwa o nazwie mniejszej od Angoli.

SELECT * 
FROM 
    panstwa 
WHERE 
    nazwa < 'Angola' 
ORDER BY 
    nazwa DESC

Rezultatem będzie lista:

+------+--------------+
| ID   | Nazwa        |
+------+--------------+
| 4    | Andora       |
+------+--------------+
| 3    | Algieria     |
+------+--------------+
| 2    | Albania      |
+------+--------------+
| 1    | Afganistan   |
+------+--------------+

Następnie ograniczamy listę do 3 rekordów poprzez klauzulę LIMIT

SELECT * 
FROM 
    panstwa 
WHERE 
    nazwa < 'Angola' 
ORDER BY 
    nazwa DESC 
LIMIT 3

Niestety mamy teraz niepoprawną kolejność rekordów, aby to naprawić musimy wynik zagnieździć w select i przesortować:

SELECT 
    * 
FROM 
    (SELECT * 
     FROM 
         panstwa 
     WHERE 
         nazwa < 'Angola' 
     ORDER BY 
         nazwa DESC 
     LIMIT 3) AS wstecz 
ORDER BY 
    nazwa

Analogiczne działania występują dla listy państw występujących po Angoli, tutaj jednak sortujemy rosnąco, gdyż rekordy poniżej zawsze będą najbliżej wybranego rekordu. Dlatego też nie ma konieczności stosowania dodatkowego zagnieżdżenia.

SELECT * 
FROM 
    panstwa 
WHERE 
    nazwa > 'Angola' 
ORDER BY 
    nazwa 
LIMIT 3

Wynik zapytania to:

+------+--------------+
| ID   | Nazwa        |
+------+--------------+
| 6    | Argentyna    |
+------+--------------+
| 7    | Armenia      |
+------+--------------+
| 8    | Australia    |
+------+--------------+

Mając już wszystkie potrzebne zapytania tworzymy z nich jedno dające oczekiwany zbiór wyników.

(SELECT * FROM (SELECT * FROM panstwa WHERE nazwa < 'Angola' ORDER BY nazwa DESC LIMIT 3) AS wstecz 
ORDER BY nazwa)
union
(SELECT * FROM panstwa where nazwa = 'Angola')
union
(SELECT * FROM panstwa WHERE nazwa > 'Angola' ORDER BY nazwa LIMIT 3)

Wynik zapytania będzie następujący:

+------+--------------+
| ID   | Nazwa        |
+------+--------------+
| 2    | Albania      |
+------+--------------+
| 3    | Algieria     |
+------+--------------+
| 4    | Andora       |
+------+--------------+
| 5    | Angola       |
+------+--------------+
| 6    | Argentyna    |
+------+--------------+
| 7    | Armenia      |
+------+--------------+
| 8    | Australia    |
+------+--------------+

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.