2009-11-13 43 views
1

在某个TABLE中,我有一个VARTEXT字段,其中包含国家代码的逗号分隔值。该字段名为cc_list。典型的条目如下所示:在目标是列的情况下使用MySQL的“IN”函数?

'DE,US,IE,GB' 

'IT,CA,US,FR,BE' 

现在给出国家代码,我希望能够有效地找到哪些记录包含该国家/地区。显然,索引这个领域没有意义。 我可以做以下

SELECT * from TABLE where cc_list LIKE '%US%'; 

但这是低效的。

由于“IN”的功能应该是有效的(其斌排序值),我正沿

SELECT * from TABLE where 'US' IN cc_list 

行思但是,这并不工作 - 我觉得第二个操作数的IN需要是一个值列表,而不是一个字符串。有没有办法将CSV字符串转换为值列表? 还有其他建议吗?谢谢!

+4

似乎最好创建一个有2个字段的表格,每个记录将TABLE记录与一个国家/地区代码相关联。 – 2009-11-13 15:50:50

+1

请问为什么你以前从未接受过某个问题的答案? – Peter 2009-11-13 15:51:39

+0

你是怎么做到的?谢谢。 – Sleepster 2009-11-13 16:01:23

回答

4
SELECT * 
FROM MYTABLE 
WHERE FIND_IN_SET('US', cc_list) 

在某个表,我有一个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_len2,在你列创建FULLTEXT指数和查询这样的:

CREATE FULLTEXT INDEX fx_mytable_cclist ON mytable (cc_list); 

SELECT * 
FROM MYTABLE 
WHERE MATCH(cc_list) AGAINST('+US' IN BOOLEAN MODE) 

这只适用于MyISAM表和参数应该是一个文本字符串(您将无法参加对日是条件)。

+0

谢谢,这是我失踪的功能! – Sleepster 2009-11-13 16:07:00

+0

不是多对多的条件非常有趣。我从来没有找到比额外表更好的解决方案。当然,那么你必须保留这张额外的表格(一些关键的限制条件会有所帮助,但是除非你使用InnoDB作为你的引擎5.x和(我认为),否则你不会得到这些) – Tom 2009-11-13 16:10:38

1

find_in_set似乎是你想要的MySql功能。如果您实际上可以将这些以逗号分隔的字符串存储为MySql sets(不超过64个可能的国家/地区,或将国家/地区分成两组,每组不超过64个),您可以继续使用find_in_set并更快一点。

1

没有有效的方法来找到你想要的。表扫描将是必要的。将多个值放入单个文本字段是对关系数据库技术的可怕滥用。如果您重构(如果您有权访问数据库结构),以便将国家代码正确存储在单独的表格中,您将能够轻松快速地检索所需的数据。

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_subtable在解析TABLEcc_listcc_list_name列单独的条目。它也涉及触发器的一些工作,因为对TABLE的每次更改都意味着必须根据需要删除/更新/插入cc_list_table中的关联行,但是这种方法适用于原始表TABLE必须保留它的原始结构,但是你可以自由地适应查询。

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

+0

谢谢,我明白这是更高效的! – Sleepster 2009-11-13 16:07:53

相关问题