Mysql
 sql >> Base de données >  >> RDS >> Mysql

Lacunes et îlots sur 2 colonnes - si colonne A consécutive et colonne B identiques

Il n'y a pas grand chose à changer dans votre requête. Vous devez essentiellement sélectionner name et number dans la sous-requête et trier dans le même ordre. Ensuite, vous pouvez grouper par name, number - rn dans la requête externe.

SELECT
    min(number) first_number,
    max(number) last_number,
    count(*) AS no_records,
    name
FROM (
    SELECT c.*, @rn := @rn + 1 rn
    from (
        SELECT name, number
        FROM `table`
        WHERE cc = 1
        ORDER BY name, number
        LIMIT 99999999999999999
    ) AS c
    CROSS JOIN (SELECT @rn := 0) r
) c
GROUP BY name, number - rn 
ORDER BY first_number ASC, name ASC;

Résultat :

first_number  last_number  no_records  name
           1            2           2  Apple
           3            3           1  Bean
          10           12           3  Hello
          14           14           1  Deer
          14           14           1  Door
          15           15           1  Hello
          17           17           1  Hello

db<>violon

Je préconise généralement contre l'utilisation des variables de session de cette manière. La raison en est que ces solutions dépendent de la mise en œuvre interne et peuvent être interrompues par des mises à jour de version ou des modifications de paramètres. Par exemple :Une fois que MariaDB a décidé d'ignorer la clause ORDER BY dans les sous-requêtes sans LIMIT. C'est pourquoi j'ai inclus une énorme LIMITE.

J'ai aussi remplacé number avec first_number dans la clause ORDER BY externe pour éviter les problèmes avec le mode ONLY_FULL_GROUP_BY.

Une manière plus stable de générer des numéros de lignes consiste à utiliser une colonne AOTO_INCREMENT dans une table temporaire :

drop temporary table if exists tmp_tbl;

create temporary table tmp_tbl (
  rn int unsigned auto_increment primary key,
  name varchar(64) not null,
  number int not null
);

insert into tmp_tbl (name, number)
  select name, number
  from `table`
  order by name, number;

La requête SELECT finale est identique à la requête externe ci-dessus :

SELECT
    min(number) first_number,
    max(number) last_number,
    count(*) AS no_records,
    name
FROM tmp_tbl
GROUP BY name, number - rn 
ORDER BY first_number ASC, name ASC;

db<>violon

Dans une version plus récente (à partir de MariaDB 10.2), vous pouvez utiliser ROW_NUMBER() fonction de fenêtre à la place :

SELECT
    min(number) first_number,
    max(number) last_number,
    count(*) AS no_records,
    name
FROM (
    SELECT
        name,
        number,
        row_number() OVER (ORDER BY name, number) as rn
    FROM `table`
    WHERE cc = 1
) c
GROUP BY name, number - rn 
ORDER BY first_number ASC, name ASC;

db<>violon