Fortlaufende Nummerierung erkennen

Thomas_Jung

Erfahrenes Mitglied
Hallo,
ich bräuchte mal einen Denkanstoß.

Ich habe folgende Zahlen in einer Tabelle.

1
3
4
5
7
8
10

Nun möchte ich das die Zahlen wie folgt ausgegeben werden.

1
3-5
7-8
10

Ich Denke das ich die Zahlen erst in ein Array speichern muss.
Aber dann?


Wie stelle ich das am gescheitesten an?


PHP:
$query= "SELECT  nummer FROM `tabelle` ORDER BY nummer";
$result = mysql_query($query);

while( $row = mysql_fetch_array( $result ) ) { 



}

Gruß Thomas
 
Ganz einfach direkt in MySQL
SQL:
SELECT
    CASE 
      WHEN MIN(prep.id) = MAX(prep.id)
      THEN MIN(prep.id)
      ELSE CONCAT(MIN(prep.id), '-', MAX(prep.id))
    END AS id_range
FROM
    (
      SELECT
          -- Letzte Gruppe als GruppenId nehmen
          @group_id AS group_id,
          t.id,
          -- Nächte Gruppe ermitteln
          @group_id := CASE
              WHEN (t.id+1) NOT IN (SELECT id FROM test)
              THEN @group_id + 1  -- Die nexte ID exisitert nicht, ergo Gruppen-ID um eins erhöhen
              ELSE @group_id      -- Due Gruppen-ID bleibt unverändert
           END AS next_group_id
      FROM
          (SELECT    @group_id := 1) vars,
          test t           
    ) prep
GROUP BY
    prep.group_id

Und hier die Spielwiese zu deiner Anfrage
http://sqlfiddle.com/#!2/76b15/23
 
Hi,

du brauchst ein zweidimensionales Array, in dem du die Werte speicherst. Du speicherst quasi ein Arrays mit Arrays aus Zahlen, das Ergebnis soll dann quasi so aussehen:

PHP:
$ranges[0][0] = 1;
$ranges[1][0] = 3;
$ranges[1][1] = 4;
$ranges[1][2] = 5;
$ranges[2][0] = 7;
$ranges[2][1] = 8;
$ranges[3][0] = 10;

Für deine Schleife brauchst du einen Zähler, der auf den aktuellen Range zeigt (fängt bei 0 an, geht nach obigen Beispiel also bis 3). Falls noch überhaupt kein Eintrag in dem Array da ist (erster Schleifendurchlauf), dann speichere einfach die erste Zahl in einem neuen Array (nach obigen Schema also in [0][0]). Bei jedem weiteren Schleifendurchlauf holst du dir von deinem aktuellen Range das letzte Element. Ist die neue Zahl genau um Eins größer als das geholte, dann speichere es in das Array hinzu. Ansonsten erstelle einen neuen Eintrag in deinem Array und speichere deine Zahl da rein.

So klar soweit? ;-)

@Yaslaw: Wow, ich bin immer wieder erstaunt, was man alles in reinem SQL anstellen kann...

// Edit: Hier mal mein ungetesteter Ansatz zur Lösung in PHP:
PHP:
$query= "SELECT  nummer FROM `tabelle` ORDER BY nummer";
$result = mysql_query($query);

$ranges = array();
$curRange = 0;

while($row = mysql_fetch_array($result)) {
	$value = $row['nummer'];

	// Noch kein Range / erste Nummer
	if(count($ranges) == 0) {
		$ranges[] = array($value);
		continue;
	}

	// Range vorhanden, letzten Wert abrufen
	$lastRangeValue = end($ranges[$curRange]);

	// Aktueller Wert um 1 größer als letzter Wert?
	if($lastRangeValue + 1 === $value) {
		$ranges[$curRange][] = $value;
		continue;
	}

	// Akteuller Wert erzeugt neuen Range
	$ranges[++$curRange][] = $value;
}

Grüße,
BK
 
Zuletzt bearbeitet:
Vielen Dank euch zwei.

@Yaslaw: Klasse SQL Code klatsch, klatsch. (Da ich später noch weitere Felder auslesen möchte ist mir der SQL Code zu kompliziert. Werde ihn aber bestimmt noch benötigen. )

@Bratkartoffel Vielen Dank.
 
@Bratkartoffel
Hi
Wenn ich z.b die Zahlen

042993
042994
042995
042996
042997
088026
088027
088028

habe ist das Ergebnis

Von 42993 BIS 88028

Und nicht 42993 - 042997 ----- 088026 bis 088028;


Ansonsten funktioniert das.

Hast du eine Idee an was das liegen kann?


Gruß Thomas
 
Hi,

keine Ahnung, bau dir mal ein paar echos bei den Zwischenschritten ein, damit du siehst wo es hakt.

Grüße,
BK
 
Um beim geliebten SQL zu bleiben. EIn Cast auf die Nummer zum vergleichen
SQL:
SELECT
    CASE 
      WHEN MIN(prep.id) = MAX(prep.id)
      THEN MIN(prep.id)
      ELSE CONCAT(MIN(prep.id), '-', MAX(prep.id))
    END AS id_range
FROM
    (
      SELECT
          -- Letzte Gruppe als GruppenId nehmen
          @group_id AS group_id,
          t.id,
          -- Nächte Gruppe ermitteln
          @group_id := CASE
              WHEN (CAST(t.id AS UNSIGNED)+1) NOT IN (SELECT CAST(id AS UNSIGNED) FROM test)
              THEN @group_id + 1  -- Die nexte ID exisitert nicht, ergo Gruppen-ID um eins erhöhen
              ELSE @group_id      -- Due Gruppen-ID bleibt unverändert
           END AS next_group_id
      FROM
          (SELECT    @group_id := 1) vars,
          test t           
    ) prep
GROUP BY
    prep.group_id
http://sqlfiddle.com/#!2/e279c7/3
Code:
ID_RANGE
042993-042997
088026-088028
 
Zuletzt bearbeitet von einem Moderator:
@Yaslaw
Dein Code funktioniert. ABER wie baue ich in deinen Code eine WHERE Abfrage mit ein

z.b
WHERE id > 5

Gruß Thomas
 
PHP:
SELECT
    CASE
      WHEN MIN(prep.id) = MAX(prep.id)
      THEN MIN(prep.id)
      ELSE CONCAT(MIN(prep.id), '-', MAX(prep.id))
    END AS id_range
FROM
    (
      SELECT
          -- Letzte Gruppe als GruppenId nehmen
          @group_id AS group_id,
          t.id,
          -- Nächte Gruppe ermitteln
          @group_id := CASE
              WHEN (CAST(t.id AS UNSIGNED)+1) NOT IN (SELECT CAST(id AS UNSIGNED) FROM test)
              THEN @group_id + 1  -- Die nexte ID exisitert nicht, ergo Gruppen-ID um eins erhöhen
              ELSE @group_id      -- Due Gruppen-ID bleibt unverändert
           END AS next_group_id
      FROM
          (SELECT    @group_id := 1) vars,
          test t
    )
	
WHERE t.id > 5

	 prep
GROUP BY
    prep.group_id

Error: (1248) Every derived table must have its own alias
 

Neue Beiträge

Zurück