我有一张桌子,像这样:
id:int | name:String | categories:String
示例行:
1 | "Lorem1" | "A, B, C"
2 | "Lorem2" | "A, B"
3 | "Lorem3" | "A, C"
4 | "Lorem4" | "B"
我还有一个表格,您可以在其中检查u所涉及的类别。这应该是选择顺序的指南。
首先,您获得具有所有选定类别的行,然后获得具有较少匹配项的行。 (如果该行没有任何类别,则不会显示)
例如有人检查:
A和B,它们应按以下顺序返回行:Lorem1,Lorem2,Lorem3,Lorem 4
A和C,它们应按以下顺序返回行:Lorem1,Lorem3,Lorem2
这就是我要做的。我对编程很陌生,并且出现了这个问题。
我也知道,也许我应该为类别和对象之间的连接创建一个新表。
答案 0 :(得分:0)
您可以使用find_in_set()
检查以逗号分隔的列表中的字符串。但是您必须先replace()
个空格。对用户选择的每个类别都这样做。然后检查find_in_set()
的结果是否大于0,因为0表示未找到任何内容,否则返回列表中大于0的位置。将这些比较的结果相加。由于布尔运算的正确性在数字上下文中为1,否则为0,因此可以按该总和递减顺序进行排序。即行匹配的内容越多,则将其放在结果中的时间越早。
类别'A'
和'C'
的示例:
SELECT *
FROM elbat
ORDER BY (find_in_set('A', replace(categories, ' ', '')) > 0)
+
(find_in_set('C', replace(categories, ' ', '')) > 0)
DESC;
您还可以使用它来排除没有匹配项的行。则总和为0。
SELECT *
FROM elbat
WHERE (find_in_set('A', replace(categories, ' ', '')) > 0)
+
(find_in_set('C', replace(categories, ' ', '')) > 0)
> 0
ORDER BY (find_in_set('A', replace(categories, ' ', '')) > 0)
+
(find_in_set('C', replace(categories, ' ', '')) > 0)
DESC;
但是用逗号分隔的列表很麻烦。您应该考虑修改架构,并使用另一个表将项目链接到类别。
答案 1 :(得分:0)
您应该在用户表中定义一个ManyToMany
字段,而不是将类别存储为字符串。因此,用户可以是一个或多个类别的一部分,反之亦然。类别表可以存储不同的类别及其各自的ID。
答案 2 :(得分:0)
您的数据的规范化版本可能是:
create table items (
id int,
name varchar(50),
primary key (id),
index (name)
);
create table categories (
id int,
name varchar(50),
primary key (id),
index (name)
);
create table items_categories (
item_id int,
category_id int,
primary key (item_id, category_id),
index (category_id, item_id),
foreign key (item_id) references items(id),
foreign key (category_id) references categories(id)
);
insert into items (id, name) values
(1, 'Lorem1'),
(2, 'Lorem2'),
(3, 'Lorem3'),
(4, 'Lorem4');
insert into categories (id, name) values
(1, 'A'),
(2, 'B'),
(3, 'C'),
(4, 'D');
insert into items_categories (item_id, category_id) values
(1, 1),
(1, 2),
(1, 3),
(2, 1),
(2, 2),
(3, 1),
(3, 3),
(4, 2);
现在-当您搜索类别“ A”和“ B”中的项目时,SELECT查询将为:
select i.*, count(*) as matches
from items i
join items_categories ic on ic.item_id = i.id
join categories c on c.id = ic.category_id
where c.name in ('A', 'B')
group by i.id
order by matches desc, i.name;
结果:
| id | name | matches |
| --- | ------ | ------- |
| 1 | Lorem1 | 2 |
| 2 | Lorem2 | 2 |
| 3 | Lorem3 | 1 |
| 4 | Lorem4 | 1 |
如果要搜索类别“ A”和“ C”,请将WHERE子句更改为
where c.name in ('A', 'C')
结果将是:
| id | name | matches |
| --- | ------ | ------- |
| 1 | Lorem1 | 2 |
| 3 | Lorem3 | 2 |
| 2 | Lorem2 | 1 |
您甚至可以使用以下方式“模仿”您的原始架构
select i.*, group_concat(c.name separator ', ') as categories
from items i
join items_categories ic on ic.item_id = i.id
join categories c on c.id = ic.category_id
group by i.id
结果:
| id | name | categories |
| --- | ------ | ---------- |
| 1 | Lorem1 | A, B, C |
| 2 | Lorem2 | A, B |
| 3 | Lorem3 | A, C |
| 4 | Lorem4 | B |
反之则很难。 (对我而言)这是使用规范化架构的主要原因。
好读的书:Is storing a delimited list in a database column really that bad?