Table Aufbau anpassen - oder Query anpassen

darkgatekeeper

Grünschnabel
Hallo,

Ich habe auf einer MySQL DB folgende Aufgabenstellung:

ID | Symbol
1 | A
2 | A
3 | C
4 | D
5 | A
6 | B
7 | B
... | ...
... | ...
256 | C


ID=Primary Key, Symbol besteht immer nur aus 4x Chars (A|B|C|D)

Die Query sollte die folgendes Ausgeben (umschrieben) - als Beispiel:

Zeige die letzte ID an, wo die Query ergibt: Symbol = "C" und das nachfolgende Symbol = "C" und das darauf folgende Symbol = "B" ist etc.

Max 8x Symbole in einer Query-Abfrage verkettet.

Falls ich es "umständlich" oder unvollständig umschrieben habe, bitte es mich wissen lassen :rolleyes:

Meine eigentlichen Fragen:

- Table Aufbau hierfür ungeeignet?
- Querie unmöglich? Workaround in PHP, weil in mysql per se unmöglich?
- Auslagern in Views bzw. "Temp-Tables"?
- Generelle Gedankenfehler?
- Sonstige Möglichkeiten?

Es läuft irgendwo auf Pattern Matching über Row-Zeilen hinaus.

Ich grübel schon eine ganze Weile, und komme wirklich nicht auf einen grünen Zweig.

Hints/Hinweise bzw. Ausräumen von Gedanken Fehlern, wie ich das ganze umbauen könnte, wären extrem hilfreich. Lösungen wären super, aber Hinweise in die richtige Richtung wären schon sehr hilfreich. Danke für jeglichen konstruktiven Vorschlag ;)!

mfg, D.G.
 
Also bei einem kurzen Test sah es so aus als ob es so klappen würde:


SQL:
SELECT t1.id, t1.symbol FROM tabelle AS t1 WHERE t1.symbol = 'A'
AND
(SELECT t2.symbol FROM tabelle AS t2 WHERE t2.id = t1.id + 1) = 'B'
AND
(SELECT t3.symbol FROM tabelle AS t3 WHERE t3.id = t1.id + 2) = 'C'
AND
(SELECT t4.symbol FROM tabelle AS t4 where t4.id = t1.id + 3) = 'D'
ORDER BY id DESC LIMIT 1

Die Tabelle enthält

Code:
 1 | A
 2 | B
 3 | A
 4 | C
 5 | D
 6 | A
 7 | B
 8 | C
 9 | D
10 | A
11 | B
12 | C
13 | D

und die Abfrage liefert als Ergebnis 10.
 
Zuletzt bearbeitet:
Hallo,

danke für das rasche Feedback, mir kommen gerade ein wenig die Augen raus :eek: Aber positiv :)

Schaue mir das mal auf der Live DB an, und gebe - heute Abend - ASAP bescheid.

Schaut aber bis dato nachvollziehbar und verständlich aus! Bin gespannt, und gebe Feedback!

lg, D.G.
 
Habe eben selber nochmal drauf geschaut, du kannst es etwas kürzer schreiben:


SQL:
SELECT t1.id, t1.symbol
FROM test AS t1
WHERE t1.symbol = 'A' AND
(
SELECT symbol
FROM test
WHERE id = t1.id + 1) = 'B' AND
(
SELECT symbol
FROM test
WHERE id = t1.id + 2) = 'C' AND
(
SELECT symbol
FROM test
WHERE id = t1.id + 3) = 'D'
/*usw.*/
ORDER BY id DESC
LIMIT 1

Der Alias für die Tabelle wird nur bei der ersten SELECT-Anweisung benötigt!
 
Oder ein wenig vereinfacht
SQL:
SELECT
	FIND_IN_SET(LOCATE('CCB', GROUP_CONCAT(IFNULL(symbol, ' ') SEPARATOR '')), GROUP_CONCAT(id)) AS myId
FROM
	(SELECT * FROM myTable ORDER BY id) AS symb;

Ich glaub, Erklärung tut not.
Als Allerestes stelle ich mittels einer Sortierung sicher, dass die Reihenfolge der Daten garantiert richtig ist.

Anschliessend überprüfe ich die Symbole mit IFNULL(symbol, ' ') ob auch alle brav abgefüllt sind. Falls welche Fehlen, werden diese durch ein Leerzeichen ersetzt.

Dann gruppiere ich alle Einträge in eine Zeile. Dann setze ich die Symbole mittels GROUP_CONCAT(IFNULL(symbol, ' ') SEPARATOR '') zu einem langem String zusammen. 'AACDAABCCBBAAC...'.
In diesem String suche ich mittels LOACET() die gesuchte Kombination. In dem Fall 'CCB'. Das gibt mir die Position vom C von CCB.

Als nächstes kombiniere ich alle ID ebenfalls mittels GROUP_COCNAT() zu einer ID-Liste die mit Kommas getrennt ist.
GROUP_CONCAT(id) ergibt also so etwas '1,2,3,5,6,10...'.

Da gehe ich nun mit der Position aud dem LOCATE() hinein und suche mir die ID an der passenden Position heraus.

Den ganzen Schritt mit der ID kannst du auch weglassen, wenn garanteirt ist, dass die IDs alle sauber abgefüllt sind
 
Zuletzt bearbeitet von einem Moderator:
Ich glaub, Erklärung tut not.

Cool wie immer wenn du was machst.

Wenn ich das aber mit meinen obigen Beispieldaten teste und nach "ABCD" suche, erhalte ich als Ergebnis die ID 6, richtig wäre aber die 10.

Irgendwo scheint also noch ein kleiner Bug versteckt zu sein!?
 
Oh, letzte ID ist gesucht, nicht erste...

Das macht es ein wenig komplizierter, da LOCATE kein Reverse kennt.

SQL:
SELECT
   FIND_IN_SET(
   	--Suche den umgekehrten String 'DCBA'
		LOCATE(
			REVERSE(@search), 
			GROUP_CONCAT(IFNULL(symbol, ' ') SEPARATOR '')
		--Und verschiebe das Resultat um Suchstringlänge-1
		) + (LENGTH(@search) -1 ), 
		GROUP_CONCAT(id)
	) AS myId
FROM
	--Den Suchwert einmal als Variable vorlegen
	(SELECT @search := 'ABCD') AS vars,
	--Die Symbole nach absteigender ID sortieren
   (SELECT * FROM symb ORDER BY id DESC) AS symb;
 
Zuletzt bearbeitet von einem Moderator:
Hab da mal noch einen anderen Ansatz ausgetestet. Dieser gibt alle Treffer zurück. Man kann nachher mit ORDER BY und LIMI auch den letzten Treffer auswählen...

SQL:
SELECT
	id,
	symbol
FROM
	(
		SELECT
			@pos := @pos + 1 AS pos,
			sy.*,
			symbstr
		FROM
			-- Alle Symbole nach ID geordnet auswählen
			(SELECT * FROM symb ORDER BY id) AS sy,
			-- Alle Variablen deklarieren und Symbole in einen String zusammenfassen
			(SELECT @pos := 0, GROUP_CONCAT(IFNULL(symbol, ' ') ORDER BY id SEPARATOR '') AS symbstr FROM symb) AS symbstr
	) AS dat
WHERE
	--Variante über SUBSTRING
	SUBSTRING(symbstr, pos, LENGTH('ABCD')) = 'ABCD';
SQL:
	--Alternatives WHERE über REGEXP
	symbstr REGEXP CONCAT('^.{',pos-1,'}ABCD');
 
Zuletzt bearbeitet von einem Moderator:
Hab da mal noch einen anderen Ansatz ausgetestet. Dieser gibt alle Treffer zurück. Man kann nachher mit ORDER BY und LIMI auch den letzten Treffer auswählen...

SQL:
SELECT
	id,
	symbol
FROM
	(
		SELECT
			@pos := @pos + 1 AS pos,
			sy.*,
			symbstr
		FROM
			-- Alle Symbole nach ID geordnet auswählen
			(SELECT * FROM symb ORDER BY id) AS sy,
			-- Alle Variablen deklarieren und Symbole in einen String zusammenfassen
			(SELECT @pos := 0, GROUP_CONCAT(IFNULL(symbol, ' ') ORDER BY id SEPARATOR '') AS symbstr FROM symb) AS symbstr
	) AS dat
WHERE
	--Variante über SUBSTRING
	SUBSTRING(symbstr, pos, LENGTH('ABCD')) = 'ABCD';
SQL:
	--Alternatives WHERE über REGEXP
	symbstr REGEXP CONCAT('^.{',pos-1,'}ABCD');

danke für das update, muss ein paar sachen durchschauen und anpassen, wie es scheint. Ein paar kleinigkeiten sind noch unklar, aber ich versuche die zu bereinigen und den thread upzudaten.

Lg, D.G.
 
Zuletzt bearbeitet von einem Moderator:
Das letzte Posting habe ich durchprobiert, entweder ich bin zu Dumm, oder es ist in der SQL Query ein Typo drinnen ...

Ich gehe nochmals Deinen Vorschlag ein paar Postings vorher durch ...

lg, D.G.
 
Zuletzt bearbeitet:
Zurück