Powiedzmy, że mam rekordy z identyfikatorami 3, 4, 7, 9 i chcę mieć możliwość przechodzenia od jednego do drugiego, nawigując za pomocą linków następny / poprzedni. Problem w tym, że nie wiem jak pobrać rekord z najbliższym wyższym ID.
Więc kiedy mam rekord o identyfikatorze 4, muszę być w stanie pobrać następny istniejący rekord, który będzie 7. Zapytanie prawdopodobnie wyglądałoby mniej więcej tak
SELECT * FROM foo WHERE id = 4 OFFSET 1
Jak mogę pobrać następny / poprzedni rekord bez pobierania całego zestawu wyników i ręcznej iteracji?
Używam MySQL 5.
Odpowiedzi:
Kolejny:
select * from foo where id = (select min(id) from foo where id > 4)
poprzedni:
select * from foo where id = (select max(id) from foo where id < 4)
źródło
Oprócz rozwiązania Cemkalyoncu :
następny rekord:
SELECT * FROM foo WHERE id > 4 ORDER BY id LIMIT 1;
poprzednie nagranie:
SELECT * FROM foo WHERE id < 4 ORDER BY id DESC LIMIT 1;
edycja: Ponieważ ta odpowiedź otrzymała ostatnio kilka pozytywnych głosów, naprawdę chcę podkreślić komentarz, który zrobiłem wcześniej, dotyczący zrozumienia, że kolumna klucza podstawowego nie jest przeznaczona jako kolumna do sortowania, ponieważ MySQL nie gwarantuje tego wyższego, automatycznie zwiększanego wartości są koniecznie dodawane w późniejszym czasie.
Jeśli Cię to nie obchodzi i po prostu potrzebujesz rekordu z wyższym (lub niższym),
id
to wystarczy. Po prostu nie używaj tego jako środka do określenia, czy rekord został faktycznie dodany później (lub wcześniej). Zamiast tego rozważ użycie kolumny z datą i godziną do sortowania według, na przykład.źródło
Wszystkie powyższe rozwiązania wymagają dwóch wywołań bazy danych. Poniższy kod sql łączy dwie instrukcje sql w jedną.
select * from foo where ( id = IFNULL((select min(id) from foo where id > 4),0) or id = IFNULL((select max(id) from foo where id < 4),0) )
źródło
DISTINCT
wcześniej*
uczyni go jeszcze lepszym, to znaczy oczywiście, jeśliid
może mieć0
wartość.id
zamiast dwóch.SELECT * FROM foo WHERE id>4 ORDER BY id LIMIT 1
źródło
SELECT * FROM foo WHERE id<4 ORDER BY id DESC LIMIT 1
dla poprzedniego rekorduPróbowałem zrobić coś podobnego, ale potrzebowałem wyników uporządkowanych według daty, ponieważ nie mogę polegać na polu ID jako kolumnie z możliwością sortowania. Oto rozwiązanie, które wymyśliłem.
Najpierw znajdujemy indeks żądanego rekordu w tabeli, kiedy jest posortowany tak, jak chcemy:
SELECT row FROM (SELECT @rownum:=@rownum+1 row, a.* FROM articles a, (SELECT @rownum:=0) r ORDER BY date, id) as article_with_rows WHERE id = 50;
Następnie pomniejsz wynik o 2 i umieść go w instrukcji limitu. Na przykład powyższe zwróciło mi 21, więc biegnę:
SELECT * FROM articles ORDER BY date, id LIMIT 19, 3
Daje Ci swój główny rekord wraz z jego następnymi i poprzednimi rekordami w podanej kolejności.
Próbowałem to zrobić jako pojedyncze wywołanie bazy danych, ale nie mogłem uzyskać instrukcji LIMIT, aby przyjąć zmienną jako jeden z jej parametrów.
źródło
Wypróbuj ten przykład.
create table student(id int, name varchar(30), age int); insert into student values (1 ,'Ranga', 27), (2 ,'Reddy', 26), (3 ,'Vasu', 50), (5 ,'Manoj', 10), (6 ,'Raja', 52), (7 ,'Vinod', 27); SELECT name, (SELECT name FROM student s1 WHERE s1.id < s.id ORDER BY id DESC LIMIT 1) as previous_name, (SELECT name FROM student s2 WHERE s2.id > s.id ORDER BY id ASC LIMIT 1) as next_name FROM student s WHERE id = 7;
Uwaga: jeśli wartość nie zostanie znaleziona, zwróci wartość null .
W powyższym przykładzie Poprzednia wartość będzie Raja, a Następna wartość będzie zerowa, ponieważ nie ma następnej wartości.
źródło
Używając podejścia @Dan, możesz tworzyć JOINs. Po prostu użyj innej @variable dla każdego zapytania podrzędnego.
SELECT current_row.row, current_row.id, previous_row.row, previous_row.id FROM ( SELECT @rownum:=@rownum+1 row, a.* FROM articles a, (SELECT @rownum:=0) r ORDER BY date, id ) as current_row LEFT JOIN ( SELECT @rownum2:=@rownum2+1 row, a.* FROM articles a, (SELECT @rownum2:=0) r ORDER BY date, id ) as previous_row ON (current_row.id = previous_row.id) AND (current_row.row = previous_row.row - 1)
źródło
current
->current_row
&previous
->previous_row
.Następny rząd
SELECT * FROM `foo` LIMIT number++ , 1
Poprzedni rząd
SELECT * FROM `foo` LIMIT number-- , 1
próbka następnego rzędu
SELECT * FROM `foo` LIMIT 1 , 1 SELECT * FROM `foo` LIMIT 2 , 1 SELECT * FROM `foo` LIMIT 3 , 1
próbka poprzedniego wiersza
SELECT * FROM `foo` LIMIT -1 , 1 SELECT * FROM `foo` LIMIT -2 , 1 SELECT * FROM `foo` LIMIT -3 , 1 SELECT * FROM `foo` LIMIT 3 , 1 SELECT * FROM `foo` LIMIT 2 , 1 SELECT * FROM `foo` LIMIT 1 , 1
źródło
Miałem ten sam problem co Dan, więc skorzystałem z jego odpowiedzi i poprawiłem ją.
Najpierw wybierz indeks wiersza, nic innego tutaj nie jest.
SELECT row FROM (SELECT @rownum:=@rownum+1 row, a.* FROM articles a, (SELECT @rownum:=0) r ORDER BY date, id) as article_with_rows WHERE id = 50;
Teraz użyj dwóch oddzielnych zapytań. Na przykład, jeśli indeks wiersza to 21, zapytanie o wybór następnego rekordu będzie wyglądać następująco:
SELECT * FROM articles ORDER BY date, id LIMIT 21, 1
Aby wybrać poprzedni rekord, użyj tego zapytania:
SELECT * FROM articles ORDER BY date, id LIMIT 19, 1
Pamiętaj, że dla pierwszego wiersza (indeks wiersza 1) limit wyniesie -1 i pojawi się błąd MySQL. Aby temu zapobiec, możesz użyć instrukcji if. Po prostu nie wybieraj niczego, ponieważ i tak nie ma poprzedniego rekordu. W przypadku ostatniego rekordu będzie następny wiersz i nie będzie żadnego wyniku.
Pamiętaj również, że jeśli używasz DESC do porządkowania, zamiast ASC, zapytania, aby wybrać następny i poprzedni wiersz, są nadal takie same, ale przełączane.
źródło
To uniwersalne rozwiązanie w warunkach dających takie same rezultaty.
<?php $your_name1_finded="somethnig searched"; //$your_name1_finded must be finded in previous select $result = db_query("SELECT your_name1 FROM your_table WHERE your_name=your_condition ORDER BY your_name1, your_name2"); //Get all our ids $i=0; while($row = db_fetch_assoc($result)) { //Loop through our rows $i++; $current_row[$i]=$row['your_name1'];// field with results if($row['your_name1'] == $your_name1_finded) {//If we haven't hit our current row yet $yid=$i; } } //buttons if ($current_row[$yid-1]) $out_button.= "<a class='button' href='/$your_url/".$current_row[$yid-1]."'>BUTTON_PREVIOUS</a>"; if ($current_row[$yid+1]) $out_button.= "<a class='button' href='/$your_url/".$current_row[$yid+1]."'>BUTTON_NEXT</a>"; echo $out_button;//display buttons ?>
źródło
Tutaj mamy sposób na pobranie poprzednich i następnych rekordów za pomocą pojedynczego zapytania MySQL. Gdzie 5 to identyfikator bieżącego rekordu.
select * from story where catagory=100 and ( id =(select max(id) from story where id < 5 and catagory=100 and order by created_at desc) OR id=(select min(id) from story where id > 5 and catagory=100 order by created_at desc) )
źródło
Jak zdobyć następny / poprzedni rekord w MySQL i PHP?
Mój przykład to zdobycie tylko identyfikatora
function btn_prev(){ $id = $_POST['ids']; $re = mysql_query("SELECT * FROM table_name WHERE your_id < '$id' ORDER BY your_id DESC LIMIT 1"); if(mysql_num_rows($re) == 1) { $r = mysql_fetch_array($re); $ids = $r['your_id']; if($ids == "" || $ids == 0) { echo 0; } else { echo $ids; } } else { echo 0; } } function btn_next(){ $id = $_POST['ids']; $re = mysql_query("SELECT * FROM table_name WHERE your_id > '$id' ORDER BY your_id ASC LIMIT 1"); if(mysql_num_rows($re) == 1) { $r = mysql_fetch_array($re); $ids = $r['your_id']; if($ids == "" || $ids == 0) { echo 0; } else { echo $ids; } } else { echo 0; } }
źródło
Optymalizacja podejścia @Don, aby używać tylko jednego zapytania
SELECT * from ( SELECT @rownum:=@rownum+1 row, CASE a.id WHEN 'CurrentArticleID' THEN @currentrow:=@rownum ELSE NULL END as 'current_row', a.* FROM articles a, (SELECT @currentrow:=0) c, (SELECT @rownum:=0) r ORDER BY `date`, id DESC ) as article_with_row where row > @currentrow - 2 limit 3
zmień CurrentArticleID na bieżący identyfikator artykułu, np
SELECT * from ( SELECT @rownum:=@rownum+1 row, CASE a.id WHEN '100' THEN @currentrow:=@rownum ELSE NULL END as 'current_row', a.* FROM articles a, (SELECT @currentrow:=0) c, (SELECT @rownum:=0) r ORDER BY `date`, id DESC ) as article_with_row where row > @currentrow - 2 limit 3
źródło
Jest jeszcze jedna sztuczka, której możesz użyć, aby wyświetlić kolumny z poprzednich wierszy, używając dowolnej kolejności, używając zmiennej podobnej do sztuczki @row:
SELECT @prev_col_a, @prev_col_b, @prev_col_c, @prev_col_a := col_a AS col_a, @prev_col_b := col_b AS col_b, @prev_col_c := col_c AS col_c FROM table, (SELECT @prev_col_a := NULL, @prev_col_b := NULL, @prev_col_c := NULL) prv ORDER BY whatever
Wygląda na to, że wybrane kolumny są oceniane w kolejności, więc najpierw wybierze zapisane zmienne, a następnie zaktualizuje zmienne do nowego wiersza (wybierając je w procesie).
NB: Nie jestem pewien, czy jest to określone zachowanie, ale użyłem go i działa.
źródło
Jeśli chcesz podać więcej niż jedno
id
zapytanie i uzyskaćnext_id
je wszystkie ...Przypisz
cur_id
w wybranym polu, a następnie wprowadź je do podzapytania, aby dostać sięnext_id
do wybranego pola. A następnie wybierz tylkonext_id
.Korzystanie z odpowiedzi Longneck do Calc
next_id
:select next_id from ( select id as cur_id, (select min(id) from `foo` where id>cur_id) as next_id from `foo` ) as tmp where next_id is not null;
źródło
CREATE PROCEDURE `pobierz_posty`(IN iduser bigint(20), IN size int, IN page int) BEGIN DECLARE start_element int DEFAULT 0; SET start_element:= size * page; SELECT DISTINCT * FROM post WHERE id_users .... ORDER BY data_postu DESC LIMIT size OFFSET start_element END
źródło
Jeśli masz kolumnę indeksu, powiedz id, możesz zwrócić poprzedni i następny identyfikator w jednym żądaniu sql. Zastąp: id swoją wartością
SELECT IFNULL((SELECT id FROM table WHERE id < :id ORDER BY id DESC LIMIT 1),0) as previous, IFNULL((SELECT id FROM table WHERE id > :id ORDER BY id ASC LIMIT 1),0) as next
źródło
Moje rozwiązanie, aby uzyskać następny i podgląd nagrania, aby wrócić do pierwszego rekordu, jeśli jestem na ostatnim i odwrotnie
Nie używam identyfikatora używam tytułu dla ładnych adresów URL
Używam Codeigniter HMVC
$id = $this->_get_id_from_url($url); //get the next id $next_sql = $this->_custom_query("select * from projects where id = (select min(id) from projects where id > $id)"); foreach ($next_sql->result() as $row) { $next_id = $row->url; } if (!empty($next_id)) { $next_id = $next_id; } else { $first_id = $this->_custom_query("select * from projects where id = (SELECT MIN(id) FROM projects)"); foreach ($first_id->result() as $row) { $next_id = $row->url; } } //get the prev id $prev_sql = $this->_custom_query("select * from projects where id = (select max(id) from projects where id < $id)"); foreach ($prev_sql->result() as $row) { $prev_id = $row->url; } if (!empty($prev_id)) { $prev_id = $prev_id; } else { $last_id = $this->_custom_query("select * from projects where id = (SELECT MAX(id) FROM projects)"); foreach ($last_id->result() as $row) { $prev_id = $row->url; } }
źródło
Oto moja odpowiedź. Biorę pomysł z „ Decent Dabbler ” i dodaję część sprawdzającą, czy id jest między min (id) a max (id). Oto część dotycząca tworzenia mojego stołu.
CREATE TABLE Users ( UserID int NOT NULL auto_increment, UserName varchar(45), UserNameID varchar(45), PRIMARY KEY (UserID)
);
Kolejnym krokiem jest utworzenie procedury składowanej odpowiedzialnej za pobranie poprzedniego identyfikatora.
CREATE DEFINER=`root`@`localhost` PROCEDURE `printPreviousIDbySelectedIDUser`( IN ID int, IN search_name varchar(45) ) BEGIN SELECT CONCAT(ns.UserID) AS 'Previous ID' from Users ns where ns.UserName=search_name AND ns.UserID IN (select min(ns.UserID) from Users ns where ns.UserID > ID union select max(ns.UserID) from Users ns where ns.UserID < ID) LIMIT 1 ; END
Pierwsza metoda jest dobra, jeśli indeksy są posortowane, ale jeśli tak nie jest. Na przykład, jeśli masz indeksy: 1,2,7 i potrzebujesz uzyskać numer 2 w ten sposób, znacznie lepiej użyj innego podejścia.
CREATE DEFINER=`root`@`localhost` PROCEDURE `getPreviousUserID`( IN ID int, IN search_name varchar(45) ) BEGIN SELECT CONCAT(ns.UserID) AS 'Previous ID' from Users ns WHERE ns.UserName=search_name AND ns.UserID < ID ORDER BY ns.UserID DESC LIMIT 1; END
źródło
100% sprawne
SELECT * FROM `table` where table_id < 3 ORDER BY `table_id` DESC limit 1
źródło
Myślę, że aby mieć rzeczywisty następny lub poprzedni wiersz w tabeli SQL, potrzebujemy wartości rzeczywistej z równymi, (<lub>) zwracającymi więcej niż jeden, jeśli chcesz zmienić pozycję wiersza w tabeli zamówień.
potrzebujemy wartości
$position
do przeszukanianeighbours
wiersza W mojej tabeli utworzyłem kolumnę 'pozycja'a zapytanie SQL do uzyskania potrzebnego wiersza to:
w następnym :
SELECT * FROM `my_table` WHERE id = (SELECT (id) FROM my_table WHERE position = ($position+1)) LIMIT 1
za poprzednie:
SELECT * FROM my_table WHERE id = (SELECT (id) FROM my_table WHERE `position` = ($position-1)) LIMIT 1
źródło
Wybierz pierwsze 1 * z foo, gdzie id> 4 uporządkuj według id rosnąco
źródło
select * from foo where id>4 order by id asc LIMIT 1