使用MySQL的“IN”函数,其中目标是一列?

时间:2009-11-13 15:47:19

标签: sql mysql

在某个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字符串转换为值列表? 还有其他建议吗?谢谢!

5 个答案:

答案 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必须保留其原始结构,但您可以根据需要随意调整查询。