我有一张桌子。字段之一是类别(由枚举表示)。有些类别的商品为零。
所以我这样做:
select category, count(*) as total from items group by category;
+------------+-------+
| category | total |
+------------+-------+
| one | 6675 |
+------------+-------+
Run Code Online (Sandbox Code Playgroud)
我想生成一个这样的表(其中两个是另一个可能的枚举值):
+------------+-------+
| category | total |
+------------+-------+
| one | 6675 |
+------------+-------+
| two | 0 |
+------------+-------+
Run Code Online (Sandbox Code Playgroud)
如何使用mysql SQL查询执行此操作?
对于那些可能的选项(值)不太多(首选<= 10)并且将来您将不会添加新选项的情况(通常不会很频繁),通常首选Enum数据类型。因此,Enum的一个好用例是性别:(m, f, n)。在您的情况下,最好是拥有所有可能类别的主表,而不是对它们使用Enum。然后,可以更容易地LEFT JOIN从Master表中进行操作。
但是,按照您的要求:
一个解决方案使用枚举类型生成表,并包含0个条目
适用于所有MySQL / MariaDB版本:
我们将需要从中获取所有可能的Enum值的列表INFORMATION_SCHEMA.COLUMNS:
SELECT
SUBSTRING(COLUMN_TYPE, 6, CHAR_LENGTH(COLUMN_TYPE) - 6) AS enum_values
FROM
information_schema.COLUMNS
WHERE
TABLE_NAME = 'items' -- your table name
AND
COLUMN_NAME = 'category' -- name of the column
AND
TABLE_SCHEMA = 'your_db' -- name of the database (schema)
Run Code Online (Sandbox Code Playgroud)
但是,此查询将为您提供所有用逗号分隔的字符串的枚举值,如下所示:
'one','two','three','four'
现在,我们需要将该字符串转换为多行。为此,我们可以使用“序列(数字系列)”表。您可以在数据库中定义一个永久表,该表存储从1到100的整数(在许多其他情况下您可能会发现此表也很有用)(或者,另一种方法是使用派生表 -选中此表可获得一个想法:https ://stackoverflow.com/a/58052199/2469308)。
CREATE TABLE seq (n tinyint(3) UNSIGNED NOT NULL, PRIMARY KEY(n));
INSERT INTO seq (n) VALUES (1), (2), ...... , (99), (100);
Run Code Online (Sandbox Code Playgroud)
现在,我们将seq基于逗号的位置在“枚举值字符串”和表之间进行JOIN操作,以将枚举值提取到不同的行中。请注意,,我们将使用','(避免在值字符串中可能出现逗号的情况),而不只是使用(逗号)来提取枚举值。字符串操作利用所Substring_Index(),Trim(),Char_Length()等功能可用于提取的枚举值。您可以检查以下答案以获得有关此技术的一般想法:
模式(在DB Fiddle上查看)
CREATE TABLE items
(id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
category ENUM('one','two','three','four'),
item_id INT UNSIGNED) ENGINE=InnoDB;
INSERT INTO items (category, item_id)
VALUES ('one', 1),
('two', 2),
('one', 2),
('one', 3);
CREATE TABLE seq (n tinyint(3) UNSIGNED NOT NULL,
PRIMARY KEY(n));
INSERT INTO seq (n) VALUES (1),(2),(3),(4),(5);
Run Code Online (Sandbox Code Playgroud)
查询#1
SELECT Trim(BOTH '\'' FROM Substring_index(Substring_index(e.enum_values,
'\',\'',
seq.n),
'\',\'', -1)) AS cat
FROM (SELECT Substring(column_type, 6, Char_length(column_type) - 6) AS
enum_values
FROM information_schema.columns
WHERE table_name = 'items'
AND column_name = 'category'
AND table_schema = 'test') AS e
JOIN seq
ON ( Char_length(e.enum_values) - Char_length(REPLACE(e.enum_values,
'\',\'',
''))
) / 3 >= seq.n - 1
| cat |
| ----- |
| one |
| two |
| three |
| four |
Run Code Online (Sandbox Code Playgroud)
现在,困难的部分已经完成。我们需要做的就是LEFT JOIN从此子查询(具有所有类别枚举值)到您的items表,以获取每个类别的计数。
最终查询如下(在DB Fiddle上查看):
SELECT all_cat.cat AS category,
Count(i.item_id) AS total
FROM (SELECT Trim(BOTH '\'' FROM Substring_index(
Substring_index(e.enum_values,
'\',\'',
seq.n),
'\',\'', -1)) AS cat
FROM (SELECT Substring(column_type, 6, Char_length(column_type) - 6)
AS
enum_values
FROM information_schema.columns
WHERE table_name = 'items'
AND column_name = 'category'
AND table_schema = 'test') AS e
JOIN seq
ON ( Char_length(e.enum_values) - Char_length(
REPLACE(e.enum_values,
'\',\'',
''))
) / 3 >= seq.n - 1) AS all_cat
LEFT JOIN items AS i
ON i.category = all_cat.cat
GROUP BY all_cat.cat
ORDER BY total DESC;
Run Code Online (Sandbox Code Playgroud)
结果
| category | total |
| -------- | ----- |
| one | 3 |
| two | 1 |
| three | 0 |
| four | 0 |
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
306 次 |
| 最近记录: |