2009-11-13 44 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

相關問題