我需要从包含如下所示字符串的列进行查询: 语言1,语言2,语言3 。
我无法为每种语言创建新列,因为它们是未定义的数量。
所以我想知道从该字符串中查询数据的最佳性能/优雅方式是什么?
我应该使用序列化数据吗?检索匹配的所有行的查询会说“Language2”?
修改 此表包含用于从我的站点搜索用户的条件索引。语言是标准之一,因此将是城市,国家和其他一些标准。问题是每个用户都可以使用不确定数量的语言。
第二次修改
以下是我现在的表格视图:
答案 0 :(得分:3)
我正在为查询序列化数组中的数据寻找相同方案的解决方案,并发现使用SUBSTRING_INDEX()
函数完成了这项工作。以下示例:
| language |
------------------------
| a:1:{i:1;s:3:"183";} |
得到数字' 183' (没有引号)查询将是:
SELECT TRIM(BOTH '"' FROM SUBSTRING_INDEX(SUBSTRING_INDEX(language,';',2),':',-1)) AS language_id
FROM language_table;
它应该在没有引号的情况下给你以下结果:
| language_id |
------------------------
| 183 |
答案 1 :(得分:2)
不,您应该规范化表架构。是的,您甚至可以处理未定义数量的值。
创建一个单独的表来保存关系引用。
<强> table_languages 强>
ref_id | language
示例数据将是:
user_id | language
-------------------
1 | Language 1
1 | Language 2
1 | Language 3
2 | Language 2
示例查询将是:
SELECT *
FROM users u
INNER JOIN languages l
ON u.user_id = l.user_id
AND l.language = 'language2'
WHERE u.country = 'abc'
AND u.city = 'def';
答案 2 :(得分:2)
虽然Shef和ajreal是正确的,但从设计的角度来看,为了规范化表格,回答实际问题,你可以使用LIKE
:
SELECT * FROM personnel WHERE languages LIKE '%English%';
但是,如果语言是自由文本,您可能会遇到问题,因为有人可能已输入“英语”或其他大写字母,因此您需要:
SELECT * FROM personnel WHERE UPPER(languages) LIKE '%ENGLISH%';
但作为一般规则,如果您的有效值是其他有效值的子字符串,则这些会变得混乱。要解决这个问题,您必须在每个序列化字符串的开头和结尾使用分隔符序列化值:
;value3;value4;value12;
这允许您搜索
LIKE '%;value1;%'
没有匹配value11
或value12
。
有时,您实际上想要子字符串匹配行为,例如,如果有人回答British English
,您可能希望English
匹配。 (但是,如果他们输入British
,你就是SOL)......但如果你遇到这些问题,你可能想要定义一个层次结构或使用编码,因为你不能依赖于子串工作
答案 3 :(得分:1)
不要这样做。
标准化的一个例子
create table language
(
id smallint(10) unsigned not null default 0,
name varchar(255) not null,
primary key(id),
key (name)
);
-- assuming your table is named as data
create table data
(
id int(10) not null default 0,
-- plus any of your existing column definition
key(id)
);
-- build a relation table to tied knot between language and data
create table data_language
(
data_id int(10) not null not null default 0,
language_id smallint(10) unsigned not null default 0,
key (data_id, language_id)
);
-- when select
select data.id, language.id, language.name
from data
inner join (data_language, language)
on data.id=data_language.data_id and language.id=data_language.language_id
where language.name='English'