Giải pháp
Tôi thực sự không biết cách chuyển danh sách ngang các giá trị được phân tách bằng dấu phẩy thành danh sách các hàng mà không cần tạo bảng chứa số, vì bạn có thể có nhiều số nhất có thể có các giá trị được phân tách bằng dấu phẩy. Nếu bạn có thể tạo bảng này, đây là câu trả lời của tôi:
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;
Lợi nhuận:
+---------------------+-----+
| 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)
Xem sqlfiddle
Giải thích
Tình huống
- Chúng tôi nối tất cả các thẻ bằng dấu phẩy để chỉ tạo một danh sách các thẻ thay vì một thẻ trên mỗi hàng
- Chúng tôi đếm xem chúng tôi có bao nhiêu thẻ trong danh sách của mình
- Chúng tôi tìm cách có thể nhận được một giá trị trong danh sách này
- Chúng tôi tìm cách có thể nhận được tất cả các giá trị dưới dạng các hàng riêng biệt
- Chúng tôi đếm các thẻ được nhóm theo giá trị của chúng
Ngữ cảnh
Hãy xây dựng lược đồ của bạn:
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");
Nối tất cả danh sách các thẻ
Chúng tôi sẽ làm việc với tất cả các thẻ trong một dòng, vì vậy chúng tôi sử dụng GROUP_CONCAT
để thực hiện công việc:
SELECT GROUP_CONCAT(tags SEPARATOR ',') FROM test;
Trả về tất cả các thẻ được phân tách bằng dấu phẩy:
Đếm tất cả các thẻ
Để đếm tất cả các thẻ, chúng tôi lấy độ dài của danh sách đầy đủ các thẻ và chúng tôi xóa độ dài của danh sách đầy đủ các thẻ sau khi thay thế ,
bởi không có gì. Chúng tôi thêm 1, vì dấu phân cách giữa hai giá trị.
SELECT LENGTH(GROUP_CONCAT(tags SEPARATOR ',')) - LENGTH(REPLACE(GROUP_CONCAT(tags SEPARATOR ','), ',', '')) + 1 AS count_tags
FROM test;
Lợi nhuận:
+------------+
| count_tags |
+------------+
| 28 |
+------------+
1 row in set (0.00 sec)
Lấy thẻ thứ N trong danh sách thẻ
Chúng tôi sử dụng SUBSTRING_INDEX
chức năng lấy
-- 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);
Với logic như vậy, để có thẻ thứ 3 trong danh sách của chúng tôi, chúng tôi sử dụng:
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(tags SEPARATOR ','), ',', 3), ',', -1)
FROM test;
Lợi nhuận:
+-------------------------------------------------------------------------------------+
| SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(tags SEPARATOR ','), ',', 3), ',', -1) |
+-------------------------------------------------------------------------------------+
| fried-rice |
+-------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
Nhận tất cả các giá trị dưới dạng các hàng riêng biệt
Ý tưởng của tôi hơi phức tạp:
- Tôi biết chúng ta có thể tạo các hàng bằng cách nối các bảng
- Tôi cần lấy thẻ thứ N trong danh sách bằng cách sử dụng yêu cầu ở trên
Vì vậy, chúng tôi sẽ tạo một bảng chứa tất cả các số từ 1 đến số thẻ tối đa mà bạn có thể có trong danh sách của mình. Nếu bạn có thể có giá trị 1M, hãy tạo 1M mục nhập từ 1 đến 1.000.000. Đối với 100 thẻ, đây sẽ là:
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 );
Bây giờ, chúng ta nhận được num
th (num là một hàng trong number
) bằng cách sử dụng truy vấn sau:
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
Lợi nhuận:
+-----+---------------------+
| 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)
Đếm số lần xuất hiện thẻ
Ngay sau khi chúng tôi có cổ điển hàng, chúng tôi có thể dễ dàng đếm số lần xuất hiện của mỗi thẻ.
Xem phần đầu của câu trả lời này để xem yêu cầu.