2017-06-02 5 views
0

Ich schreibe ein PHP-Paket, wobei ich eine Reihe von "Dokumenten" mit jeweils eigenen Attributen speichern muss, die in Menge, Name variieren können und die Art, wie nur die Attribute für verschiedene Arten von Produkten unterscheiden können (zB ein Schuh kann ein Material, Farbe und Stil, aber ein Smartphone kann ein Betriebssystem, Gewicht, Größe usw.)MySQL: Alternative zu JSON für ältere Versionen/Speichern und Abfragen mehrerer Werte in einer Spalte

| id | name  | 
|-----|------------| 
| 1 | Acme Shoe | 
| 2 | Acme Phone | 

ich mag um alle meine Dokumente oder Produkte nach ihren Attributen abfragen zu können. Die Abfragen können von einem sehr einfachen WHERE attribute_a = value_a zu einem viel komplizierter verschachtelten Satz von Klauseln reichen, wie WHERE ((attribute_a = value_a OR attribute_a > value_b) AND attribute_b LIKE '%pattern%')

Mein ideales Szenario die native JSON-Unterstützung von MySQL lieferte wäre die Verwendung 5.7+ und MariaDB 10.2+ die Attribute zu speichern, gegen jedes Dokument und verwenden Sie die handliche JSON_EXTRACT Funktion, um jedes Attribut zu extrahieren, das ich abfragen möchte.

Leider muss mein Paket in der Lage sein, ältere Versionen von MySQL und MariaDB zu unterstützen. Ich hatte überlegt, JSON in einem TEXT- oder LONGTEXT-Feld zu speichern und REGEX zu verwenden, um die Werte der Attribute auszuwerten, die ich beim Vergleich benötige, aber ich kann mir vorstellen, dass dies unglaublich ressourcenintensiv und langsam wäre. Bitte korrigieren Sie mich, falls ich falsch liege.

So wie es aussieht, ich fühle mich wie ich in gehen für eine EAV Typ Lösung gesperrt bin:

| id | name  | 
|-----|------------| 
| 1 | Acme Shoe | 
| 2 | Acme Phone | 


| id | document_id | key  | value | 
|-----|-------------|----------|---------| 
| 1 | 1   | material | canvas | 
| 2 | 1   | color | black | 
| 3 | 2   | os  | android | 
| 4 | 2   | weight | 100  | 

Finden der Dokumente mit einer WHERE-Klausel relativ trivial ist:

SELECT DISTINCT(document_id) 
FROM document_attributes 
WHERE key = 'material' 
AND value = 'canvas' 

jedoch Ich habe keine Ahnung, wie ich kompliziertere WHERE-Klauseln umsetzen würde. Das Problem besteht insbesondere darin, dass die Attribute in separaten Zeilen gespeichert sind. Z.B.

  • Die Dokumente erhalten, die Canvas-Material UND schwarz gefärbt haben.
  • die Dokumente erhalten, die Android-Betriebssystem haben und Gewicht entweder, 1 oder größer als 99.

Ratschläge oder Empfehlungen würden sehr geschätzt.


bearbeiten

Nach einiger Überlegung mit dem EAV Ansatz, das beste, das ich es geschafft haben, mit so weit kommen wird, um die Attribute Tabelle in die Dokumente Tabelle für jedes Attribut wiederholt Beitritt in der Abfrage beteiligt . Von dort aus kann ich den Wert jedes Attributs in der WHERE-Klausel verwenden. Zum Beispiel werden alle Produkte der Auswahl, wo das Attribut „Material“ ist „Leinwand“ oder das „Gewicht“ ist größer als 99:

SELECT d.id AS id, a1.value AS material, a2.value AS weight 
FROM documents AS d 
LEFT JOIN attributes AS a1 ON a1.document_id = d.id AND a1.name = 'material' 
LEFT JOIN attributes AS a2 ON a2.document_id = d.id AND a2.name = 'weight' 
WHERE a1.value = 'canvas' 
AND a2.value > 99 

Dies ergibt erscheint:

| id | material | weight | 
|----|----------|--------| 
| 1 | canvas | NULL | 
| 2 | NULL  | 100 | 

Antwort

1

Unter der Annahme des document_id/Schlüssel/Wert-Kombination ist einzigartig, Sie könnten so etwas tun:

SELECT document_id FROM example 
WHERE `key`='material' AND `value`='canvas' 
OR `key`='color' AND `value`='black' 
GROUP BY document_id 
HAVING COUNT(*) = 2; 

SELECT document_id FROM example 
WHERE `key`='os' AND `value`='android' 
OR (`key`='weight' AND (`value` = 1) OR (`value` > 99)) 
GROUP BY document_id 
HAVING COUNT(*) = 2; 
+0

Vielen Dank für Ihre Antwort. Ich mag den Ansatz.Ich nehme an, dass die "2" im "HAVING" -Teil sich auf die Anzahl der Attribute bezieht, die Sie vergleichen. Haben Sie eine Idee, wie sich dies auf noch kompliziertere Abfragen ausweiten würde, bei denen wir mehr Attribute auf verschiedene Arten vergleichen und sie anders verschachteln? Ich habe gerade den Gedanken gehabt, potentiell für jedes zu vergleichende Attribut in die Attributtabelle einzusteigen und dann die where-Klausel für diese verbundenen Attribute zu erstellen. Siehst du das arbeiten? – Jonathon

Verwandte Themen