2013-01-04 42 views
1

我有一個mysql表,其中包含一些隨機組合的數字。爲簡單起見,以下表爲例:組合/值的mysql分配

index|n1|n2|n3 
1  1 2 3 
2  4 10 32 
3  3 10 4 
4  35 1 2 
5  27 1 3 
etc 

我想知道的是組合發生在表中的次數。例如,發生4次10次或1次2次或1次2次或3次10 4次等組合的次數。

我是否必須創建另一張包含所有可能組合的表格,並從那裏進行比較,或者是否有另一種方法來執行此操作?

+0

現在我認爲一個解決方案是爲所有可能的3組合等生成一張表,爲所有可能的4組合等生成一個表。然後爲每個表做一個select *並在java中做一個交集並保持一個計數。但這似乎放棄了沉重。我想知道是否有更簡單的方法來做到這一點。 –

回答

0
SELECT 
    CONCAT(CAST(n1 AS VARCHAR(10)),'|',CAST(n2 AS VARCHAR(10)),'|',CAST(n3 AS VARCHAR(10))) AS Combination, 
    COUNT(CONCAT(CAST(n1 AS VARCHAR(10)),'|',CAST(n2 AS VARCHAR(10)),'|',CAST(n3 AS VARCHAR(10)))) AS Occurrences 
FROM 
    MyTable 
GROUP BY 
    CONCAT(CAST(n1 AS VARCHAR(10)),'|',CAST(n2 AS VARCHAR(10)),'|',CAST(n3 AS VARCHAR(10))) 

這創建了一個單列,通過連接這些值來表示3列中值的組合。它會統計每個事件的發生。

+0

感謝您的代碼,你能否解釋一下以及它是如何工作的? –

+0

mysql讓我在你的代碼上出錯。我將嘗試去玩弄它,看看我能否得到它的工作.. –

+1

你可以通過使用CONCAT_WS()來簡化那些長'CONCAT()'表達式。 – Barmar

1

對於單一組合,這很容易:

SELECT COUNT(*) 
FROM my_table 
WHERE n1 = 3 AND n2 = 10 AND n3 = 4 

如果你想與多個組合要做到這一點,你可以創建它們的(臨時)表,並加入該表與您的數據,像這樣的:

CREATE TEMPORARY TABLE combinations (
    id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
    n1 INTEGER, n2 INTEGER, n3 INTEGER 
); 

INSERT INTO combinations (n1, n2, n3) VALUES 
    (1, 2, NULL), (4, 10, NULL), (1, 2, 3), (3, 10, 4); 

SELECT c.n1, c.n2, c.n3, COUNT(t.id) AS num 
FROM combinations AS c 
    LEFT JOIN my_table AS t 
    ON (c.n1 = t.n1 OR c.n1 IS NULL) 
    AND (c.n2 = t.n2 OR c.n2 IS NULL) 
    AND (c.n3 = t.n3 OR c.n3 IS NULL) 
GROUP BY c.id; 

demo on SQLize

注意書面此查詢是不是很有效,由於OR c.n? IS NULL條款,這MySQL的智能不夠優化。如果您的所有組合都包含相同數量的術語,則可以將它們排除,這將允許查詢使用數據表上的索引。

詩篇。通過上面的查詢,組合(1, 2, NULL)將不匹配(35, 1, 2)。然而,(NULL, 1, 2)將如此,如果你想要兩者,一個簡單的解決方法是將兩種模式都包含在你的組合表中。

如果實際上列中的列數比示例中顯示的多得多,並且您希望匹配任何連續列中出現的模式,那麼您應該將列打包爲字符串並使用LIKEREGEXP查詢。例如,如果您連接您的所有數據列到一個名爲data列逗號分隔的字符串,你可以搜索這樣的:

INSERT INTO combinations (pattern) VALUES 
    ('1,2'), ('4,10'), ('1,2,3'), ('3,10,4'), ('7,8,9'); 

SELECT c.pattern, COUNT(t.id) AS num 
FROM combinations AS c 
    LEFT JOIN my_table AS t 
    ON CONCAT(',', t.data, ',') LIKE CONCAT('%,', c.pattern, ',%') 
GROUP BY c.id; 

demo on SQLize

你可以把這個查詢有所加快通過在表中添加前綴和後綴的CONCAT()部分實際數據,但是如果你有很多數據要搜索,這仍然是一個相當低效的查詢,因爲它不能使用索引。如果你需要這樣的子字符串有效地搜索大型數據集,你可能想要使用比MySQL更適合特定用途的東西。

+0

是的單身是很容易的,但我必須爲多個。我正在寫一個Java應用程序來做到這一點。所以我的方法是創建另一個表,其中包含所有可能的組合,並在java中執行加入或交叉,即使這似乎已退出昂貴的操作。 –

+0

我已經退出了一些更簡單的列,這使得它更復雜一些。組合總數約爲200萬。 –

+0

在這種情況下,將數據存儲爲字符串確實會更好一些;見上面的編輯。 –

1

表格中只有三列,因此您正在查找1,2和3個元素的組合。

爲了簡單起見,我會在下表開始:

select index, n1 as n from t union all 
select index, n2 from t union all 
select index, n3 from t union all 
select distinct index, -1 from t union all 
select distinct index, -2 from t 

我們稱之爲「價值」。現在,我們希望從該表中獲得給定索引的所有三元組。在這種情況下,-1和-2表示NULL。

select (case when v1.n < 0 then NULL else v1.n end) as n1, 
     (case when v2.n < 0 then NULL else v2.n end) as n2, 
     (case when v3.n < 0 then NULL else v3.n end) as n3, 
     count(*) as NumOccurrences 
from values v1 join 
    values v2 
    on v1.n < v2.n and v1.index = v2.index join 
    values v3 
    on v2.n < v3.n and v2.index = v3.index 

這是使用連接機制來生成組合。

該方法可以查找所有組合,無論排序如何(所以1,2,3都與2,3,1相同)。此外,這會忽略重複項,所以如果2重複兩次,它就無法找到(1,2,2)。

+0

戈登,謝謝我以後再試,看看它是如何工作的。我想你也可以擴大到7列,如果需要? –

+0

@SoucianceEqdamRashti。 。 。是。在中間表中,您需要六個「select distinct」行,以處理少於7個項目的組合。 –