在某个TABLE中,我有一个VARTEXT字段,其中包含逗号分隔的国家/地区代码值。该字段名为cc_list。典型条目如下所示:
'DE,US,IE,GB'
'IT,CA,US,FR,BE'
现在给出国家代码,我希望能够有效地找到包含该国家/地区的记录。显然,索引此字段没有意义。 我可以做以下
SELECT * from TABLE where cc_list LIKE '%US%';
但这效率很低。
由于“IN”函数应该是有效的(它对值进行bin分类),我正在思考
SELECT * from TABLE where 'US' IN cc_list
但是这不起作用 - 我认为IN的第二个操作数需要是一个值列表,而不是一个字符串。有没有办法将CSV字符串转换为值列表? 还有其他建议吗?谢谢!
答案 0 :(得分:4)
SELECT *
FROM MYTABLE
WHERE FIND_IN_SET('US', cc_list)
在某个TABLE中,我有一个VARTEXT字段,其中包含逗号分隔的国家/地区代码值。
如果您希望查询有效,则应创建多对多链接表:
CREATE TABLE table_country (cc CHAR(2) NOT NULL, tableid INT NOT NULL, PRIMARY KEY (cc, tableid))
SELECT *
FROM tablecountry tc
JOIN mytable t
ON t.id = tc.tableid
WHERE t.cc = 'US'
或者,您可以将ft_min_word_len
设置为2
,在列上创建FULLTEXT
索引并进行如下查询:
CREATE FULLTEXT INDEX fx_mytable_cclist ON mytable (cc_list);
SELECT *
FROM MYTABLE
WHERE MATCH(cc_list) AGAINST('+US' IN BOOLEAN MODE)
这仅适用于MyISAM
表,参数应该是文字字符串(在这种情况下你将无法加入)。
答案 1 :(得分:2)
规范化的第一条规则是,出于这个原因,您应该将cc_list
等多值列更改为单个值字段。
最好在其自己的表格中,每个国家/地区代码都有ID,支持多对多关系的数据透视表。
CREATE TABLE my_table (
my_id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
mystuff VARCHAR NOT NULL,
PRIMARY KEY(my_id)
);
# this is the pivot table
CREATE TABLE my_table_countries (
my_id INT(11) UNSIGNED NOT NULL,
country_id SMALLINT(5) UNSIGNED NOT NULL,
PRIMARY KEY(my_id, country_id)
);
CREATE TABLE countries {
country_id SMALLINT(5) UNSIGNED NOT NULL AUTO_INCREMENT,
country_code CHAR(2) NOT NULL,
country_name VARCHAR(100) NOT NULL,
PRIMARY KEY (country_id)
);
然后您可以使用索引查询它:
SELECT * FROM my_table JOIN my_table_countries USING (my_id) JOIN countries USING (country_id) WHERE country_code = 'DE'
SELECT * FROM my_table JOIN my_table_countries USING (my_id) JOIN countries USING (country_id) WHERE country_code IN('DE','US')
您可能需要将结果分组为my_id
。
答案 2 :(得分:1)
find_in_set似乎是你想要的MySql函数。如果您实际上可以将这些以逗号分隔的字符串存储为MySql sets(不超过64个可能的国家/地区,或将国家/地区分成两组,每组不超过64个),您可以继续使用find_in_set
并继续快一点。
答案 3 :(得分:1)
没有有效的方法可以找到你想要的东西。需要进行表扫描。将多个值放入单个文本字段是对关系数据库技术的可怕滥用。如果您重构(如果您有权访问数据库结构),以便国家/地区代码正确存储在单独的表中,您将能够轻松快速地检索所需的数据。
答案 4 :(得分:0)
我之前成功使用过的一种方法(不是在mysql上)是在表上放置一个触发器,它将值(基于特定的分隔符)拆分为离散值,并将它们插入到子表中。您的选择可以如下所示:
SELECT * from TABLE where cc_list IN
(
select cc_list_name from cc_list_subtable
where c_list_subtable.table_id = TABLE.id
)
触发器将cc_list
中的TABLE
解析为表cc_list_name
中列cc_list_subtable
中的单独条目。它也涉及触发器中的一些工作,因为对TABLE
的每次更改都意味着必须根据需要删除/更新/插入cc_list_table中的关联行,但这种方法适用于原始表的情况TABLE
必须保留其原始结构,但您可以根据需要随意调整查询。