web-dev-qa-db-fra.com

MySql - Comment obtenir une valeur dans la ligne précédente et une valeur dans la ligne suivante?

J'ai le tableau suivant, nommé Example:

id(int 11) //not autoincriment
value (varchar 100)

Il contient les lignes de données suivantes:

0  100
2  150
3  200
6  250
7  300

Notez que les valeurs id ne sont pas contiguës.

J'ai écrit ce SQL jusqu'à présent:

SELECT * FROM Example WHERE id = 3

Cependant, je ne sais pas comment obtenir la valeur de id précédente et celle de la suivante id...

S'il vous plaît aidez-moi à obtenir la valeur précédente et la valeur suivante si id = 3?

P.S .: dans mon exemple, ce sera: précédent - 150, suivant - 250.

11
user2881809

Sélectionnez la ligne suivante ci-dessous:

SELECT * FROM Example WHERE id < 3 ORDER BY id DESC LIMIT 1

Sélectionnez la ligne suivante ci-dessus:

SELECT * FROM Example WHERE id > 3 ORDER BY id LIMIT 1

Sélectionnez les deux dans une requête, par exemple. utilisez UNION :

(SELECT * FROM Example WHERE id < 3 ORDER BY id DESC LIMIT 1)
 UNION
(SELECT * FROM Example WHERE id > 3 ORDER BY id LIMIT 1)

C'est ce que tu veux dire?

17
Jonny 5

Une solution serait d'utiliser des variables temporaires:

select 
    @prev as previous,
    e.id,
    @prev := e.value as current
from
    (
        select
            @prev := null
    ) as i,
    example as e
order by
    e.id

Pour obtenir la valeur "next", répétez la procédure. Voici un exemple:

select 
  id, previous, current, next
from
  (
    select
      @next as next,
      @next := current as current,
      previous,
      id
    from
      (
        select @next := null
      ) as init,
      (
        select
          @prev as previous,
          @prev := e.value as current,
          e.id
        from
          (
            select @prev := null
          ) as init,
          example as e
        order by e.id
      ) as a
    order by
      a.id desc
  ) as b
order by
  id

Vérifiez l'exemple sur SQL Fiddle

Peut-être exagéré, mais cela peut vous aider

11
Barranka

s'il vous plaît essayez ceci sqlFiddle

SELECT value,
       (SELECT value FROM example e2
        WHERE e2.value < e1.value
        ORDER BY value DESC LIMIT 1) as previous_value,
       (SELECT value FROM example e3
        WHERE e3.value > e1.value
        ORDER BY value ASC LIMIT 1) as next_value
FROM example e1
WHERE id = 3

Edit: OP mentionné pour récupérer la valeur de idet la valeur de iddans un des commentaires afin que le code soit ici SQLFiddle

SELECT value,
      (SELECT value FROM example e2
       WHERE e2.id < e1.id
       ORDER BY id DESC LIMIT 1) as previous_value,
      (SELECT value FROM example e3
       WHERE e3.id > e1.id
       ORDER BY id ASC LIMIT 1) as next_value
FROM example e1
WHERE id = 3
6
Tin Tran
SELECT *,
       (SELECT value FROM example e1 WHERE e1.id < e.id ORDER BY id DESC LIMIT 1 OFFSET 0) as prev_value,
       (SELECT value FROM example e2 WHERE e2.id > e.id ORDER BY id ASC LIMIT 1 OFFSET 0) as next_value
FROM example e
WHERE id=3;

Et vous pouvez placer votre propre décalage après le mot clé OFFSET si vous souhaitez sélectionner des enregistrements avec des décalages plus élevés pour les valeurs suivantes et précédentes de l'enregistrement sélectionné.

4
Mojtaba Rezaeian

Cette requête utilise une variable définie par l'utilisateur pour calculer la distance à partir de l'ID cible et une série de requêtes d'encapsulation pour obtenir les résultats souhaités. Un seul passage est fait sur la table, il devrait donc bien fonctionner.

select * from (
    select id, value from (
        select *, (@x := ifnull(@x, 0) + if(id > 3, -1, 1)) row from (
            select * from mytable order by id
        ) x 
    ) y
    order by row desc
    limit 3
) z
order by id

Voir un SQLFiddle

Si vous ne vous souciez pas de l'ordre final des lignes, vous pouvez omettre la requête wrapper la plus externe.

1
Bohemian

Voici ma solution peut vous convenir:

SELECT * FROM Example
WHERE id IN (
(SELECT MIN(id) FROM Example WHERE id > 3),(SELECT MAX(id) FROM Example WHERE id < 3)
)

Démo: http://sqlfiddle.com/#!9/36c1d/2

1
Alexander

Si vous n'avez pas d'identifiant, cela a fonctionné pour moi.

Suivant: Sélectionnez * dans le nom de la table où nom de colonne> ordre actuel des données de colonne par nom de colonne Limite ASC 1

Précédent: Sélectionnez * dans le nom de la table où nom de colonne <ordre actuel des données de colonne par nom de colonne DESC limite 1

J'utilise ceci pour une liste de membres où la recherche est sur le nom de famille du membre. Tant que vous avez les données de l'enregistrement actuel, cela fonctionne bien.

0
Jeff

Une solution possible si vous avez besoin de tout cela dans une rangée

SELECT t.id, t.value, prev_id, p.value prev_value, next_id, n.value next_value
  FROM
(
  SELECT t.id, t.value,
  (
    SELECT id
      FROM table1
     WHERE id < t.id
     ORDER BY id DESC
     LIMIT 1
  ) prev_id,
  (
    SELECT id
      FROM table1
     WHERE id > t.id
     ORDER BY id
     LIMIT 1
  ) next_id
    FROM table1 t
   WHERE t.id = 3
) t LEFT JOIN table1 p
     ON t.prev_id = p.id LEFT JOIN table1 n
     ON t.next_id = n.id 

Exemple de sortie:

 ID | Valeur | PREV_ID | PREV_VALUE | NEXT_ID | NEXT_VALUE | 
 | ---- | ------- | --------- | ------------ | -------- - | ------------ | 
 | 3 | 200 | 2 | 150 | 4 | 250 | 

Voici SQLFiddle démo

0
peterm