Mysql
 sql >> Datenbank >  >> RDS >> Mysql

MySql PHP wählt die Anzahl unterschiedlicher Werte aus kommagetrennten Daten (Tags) aus

Lösung

Ich weiß nicht wirklich, wie ich eine horizontale Liste von durch Kommas getrennten Werten in eine Liste von Zeilen umwandeln kann, ohne eine Tabelle mit Zahlen zu erstellen, so viele Zahlen wie Sie durch Kommas getrennte Werte haben können. Wenn Sie diese Tabelle erstellen können, hier ist meine Antwort:

SELECT 
  SUBSTRING_INDEX(SUBSTRING_INDEX(all_tags, ',', num), ',', -1) AS one_tag,
  COUNT(*) AS cnt
FROM (
  SELECT
    GROUP_CONCAT(tags separator ',') AS all_tags,
    LENGTH(GROUP_CONCAT(tags SEPARATOR ',')) - LENGTH(REPLACE(GROUP_CONCAT(tags SEPARATOR ','), ',', '')) + 1 AS count_tags
  FROM test
) t
JOIN numbers n
ON n.num <= t.count_tags
GROUP BY one_tag
ORDER BY cnt DESC;

Rückgabe:

+---------------------+-----+
| one_tag             | cnt |
+---------------------+-----+
| chicken             |   5 |
| pork                |   4 |
| spaghetti           |   3 |
| fried-rice          |   2 |
| manchurain          |   2 |
| pho                 |   1 |
| chicken-calzone     |   1 |
| fettuccine          |   1 |
| chorizo             |   1 |
| meat-balls          |   1 |
| miso-soup           |   1 |
| chanko-nabe         |   1 |
| chicken-manchurian  |   1 |
| pork-manchurian     |   1 |
| sweet-and-sour-pork |   1 |
| peking-duck         |   1 |
| duck                |   1 |
+---------------------+-----+
17 rows in set (0.01 sec)

Siehe sqlfiddle

Erklärung

Szenario

  1. Wir verketten alle Tags mit einem Komma, um nur eine Liste von Tags statt einer pro Zeile zu erstellen
  2. Wir zählen, wie viele Tags wir in unserer Liste haben
  3. Wir finden heraus, wie wir einen Wert in dieser Liste erhalten können
  4. Wir finden heraus, wie wir alle Werte als getrennte Zeilen erhalten können
  5. Wir zählen Tags gruppiert nach ihrem Wert

Kontext

Lassen Sie uns Ihr Schema erstellen:

CREATE TABLE test (
    id INT PRIMARY KEY,
    tags VARCHAR(255)
);

INSERT INTO test VALUES
    ("1",         "pho,pork"),
    ("2",         "fried-rice,chicken"),
    ("3",         "fried-rice,pork"),
    ("4",         "chicken-calzone,chicken"),
    ("5",         "fettuccine,chicken"),
    ("6",         "spaghetti,chicken"),
    ("7",         "spaghetti,chorizo"),
    ("8",         "spaghetti,meat-balls"),
    ("9",         "miso-soup"),
    ("10",        "chanko-nabe"),
    ("11",        "chicken-manchurian,chicken,manchurain"),
    ("12",        "pork-manchurian,pork,manchurain"),
    ("13",        "sweet-and-sour-pork,pork"),
    ("14",        "peking-duck,duck");

Alle Tag-Listen verketten

Wir werden mit allen Tags in einer einzigen Zeile arbeiten, also verwenden wir GROUP_CONCAT um die Arbeit zu erledigen:

SELECT GROUP_CONCAT(tags SEPARATOR ',') FROM test;

Gibt alle Tags getrennt durch ein Komma zurück:

Alle Tags zählen

Um alle Tags zu zählen, erhalten wir die Länge der vollständigen Tag-Liste und entfernen die Länge der vollständigen Tag-Liste nach dem Ersetzen von , durch nichts. Wir fügen 1 hinzu, da das Trennzeichen zwischen zwei Werten steht.

SELECT LENGTH(GROUP_CONCAT(tags SEPARATOR ',')) - LENGTH(REPLACE(GROUP_CONCAT(tags SEPARATOR ','), ',', '')) + 1 AS count_tags
FROM test;

Rückgabe:

+------------+
| count_tags |
+------------+
|         28 |
+------------+
1 row in set (0.00 sec)

N-tes Tag in der Tag-Liste abrufen

Wir verwenden den SUBSTRING_INDEX Funktion, um

zu erhalten
-- returns the string until the 2nd delimiter\'s occurrence from left to right: a,b
SELECT SUBSTRING_INDEX('a,b,c', ',', 2);

-- return the string until the 1st delimiter, from right to left: c
SELECT SUBSTRING_INDEX('a,b,c', ',', -1);

-- we need both to get: b (with 2 being the tag number)
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('a,b,c', ',', 2), ',', -1);

Mit einer solchen Logik verwenden wir, um das dritte Tag in unserer Liste zu erhalten:

SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(tags SEPARATOR ','), ',', 3), ',', -1)
FROM test;

Rückgabe:

+-------------------------------------------------------------------------------------+
| SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(tags SEPARATOR ','), ',', 3), ',', -1) |
+-------------------------------------------------------------------------------------+
| fried-rice                                                                          |
+-------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

Erhalte alle Werte als getrennte Zeilen

Meine Idee ist ein wenig knifflig:

  1. Ich weiß, dass wir Zeilen erstellen können, indem wir Tabellen verbinden
  2. Ich muss das N-te Tag in der Liste mit der obigen Anfrage abrufen

Wir erstellen also eine Tabelle mit allen Zahlen von 1 bis zur maximalen Anzahl von Tags, die Sie möglicherweise in Ihrer Liste haben. Wenn Sie 1M-Werte haben können, erstellen Sie 1M-Einträge von 1 bis 1.000.000. Für 100 Tags ist dies:

CREATE TABLE numbers (
  num INT PRIMARY KEY
);

INSERT INTO numbers VALUES
    ( 1 ), ( 2 ), ( 3 ), ( 4 ), ( 5 ), ( 6 ), ( 7 ), ( 8 ), ( 9 ), ( 10 ), 
    ( 11 ), ( 12 ), ( 13 ), ( 14 ), ( 15 ), ( 16 ), ( 17 ), ( 18 ), ( 19 ), ( 20 ), 
    ( 21 ), ( 22 ), ( 23 ), ( 24 ), ( 25 ), ( 26 ), ( 27 ), ( 28 ), ( 29 ), ( 30 ), 
    ( 31 ), ( 32 ), ( 33 ), ( 34 ), ( 35 ), ( 36 ), ( 37 ), ( 38 ), ( 39 ), ( 40 ), 
    ( 41 ), ( 42 ), ( 43 ), ( 44 ), ( 45 ), ( 46 ), ( 47 ), ( 48 ), ( 49 ), ( 50 ), 
    ( 51 ), ( 52 ), ( 53 ), ( 54 ), ( 55 ), ( 56 ), ( 57 ), ( 58 ), ( 59 ), ( 60 ), 
    ( 61 ), ( 62 ), ( 63 ), ( 64 ), ( 65 ), ( 66 ), ( 67 ), ( 68 ), ( 69 ), ( 70 ), 
    ( 71 ), ( 72 ), ( 73 ), ( 74 ), ( 75 ), ( 76 ), ( 77 ), ( 78 ), ( 79 ), ( 80 ), 
    ( 81 ), ( 82 ), ( 83 ), ( 84 ), ( 85 ), ( 86 ), ( 87 ), ( 88 ), ( 89 ), ( 90 ), 
    ( 91 ), ( 92 ), ( 93 ), ( 94 ), ( 95 ), ( 96 ), ( 97 ), ( 98 ), ( 99 ), ( 100 );

Jetzt erhalten wir die num th (num ist eine Zeile in number ) mit der folgenden Abfrage:

SELECT n.num, SUBSTRING_INDEX(SUBSTRING_INDEX(all_tags, ',', num), ',', -1) as one_tag
FROM (
  SELECT
    GROUP_CONCAT(tags SEPARATOR ',') AS all_tags,
    LENGTH(GROUP_CONCAT(tags SEPARATOR ',')) - LENGTH(REPLACE(GROUP_CONCAT(tags SEPARATOR ','), ',', '')) + 1 AS count_tags
  FROM test
) t
JOIN numbers n
ON n.num <= t.count_tags

Rückgabe:

+-----+---------------------+
| num | one_tag             |
+-----+---------------------+
|   1 | pho                 |
|   2 | pork                |
|   3 | fried-rice          |
|   4 | chicken             |
|   5 | fried-rice          |
|   6 | pork                |
|   7 | chicken-calzone     |
|   8 | chicken             |
|   9 | fettuccine          |
|  10 | chicken             |
|  11 | spaghetti           |
|  12 | chicken             |
|  13 | spaghetti           |
|  14 | chorizo             |
|  15 | spaghetti           |
|  16 | meat-balls          |
|  17 | miso-soup           |
|  18 | chanko-nabe         |
|  19 | chicken-manchurian  |
|  20 | chicken             |
|  21 | manchurain          |
|  22 | pork-manchurian     |
|  23 | pork                |
|  24 | manchurain          |
|  25 | sweet-and-sour-pork |
|  26 | pork                |
|  27 | peking-duck         |
|  28 | duck                |
+-----+---------------------+
28 rows in set (0.01 sec)

Tag-Vorkommen zählen

Sobald wir jetzt classic haben Zeilen können wir das Vorkommen jedes Tags einfach zählen.

Siehe oben in dieser Antwort um die Anfrage zu sehen.