1

数字のランダムな組み合わせを含む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

私が知りたいのは、テーブルで組み合わせが発生した回数です。たとえば、410または12または123または3104などの組み合わせが何回発生したか。

可能なすべての組み合わせを含む別のテーブルを作成し、そこから比較する必要がありますか、それともこれを行う別の方法がありますか?

4

3 に答える 3

1

テーブルには 3 つの列しかないため、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 が 2 回繰り返されると (1, 2, 2) を見つけることができません。

于 2013-01-04T02:21:36.947 に答える
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;

( SQLize のデモ)

記述されたこのクエリはOR c.n? IS NULL、MySQL が最適化するほどスマートではない句のためにあまり効率的ではないことに注意してください。すべての組み合わせに同じ数の用語が含まれている場合は、それらを除外できます。これにより、クエリでデータ テーブルのインデックスを利用できるようになります。

Ps。上記のクエリでは、組み合わせ(1, 2, NULL)が一致しません(35, 1, 2)。ただし、(NULL, 1, 2)両方が必要な場合は、組み合わせの表に両方のパターンを含めるだけで簡単に回避できます。

例に示されているよりも多くの列が実際にあり、連続する列の任意のセットで発生するパターンを一致させたい場合は、列を文字列にパックしてLIKEorREGEXPクエリを使用する必要があります。たとえば、すべてのデータ列を という名前の列でコンマ区切りの文字列に連結すると、次の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;

( SQLize のデモ)

テーブル内の実際のデータの一部に接頭辞と接尾辞を追加することで、このクエリをいくらか高速化できCONCAT()ますが、検索するデータが大量にある場合、これは使用できないため、かなり非効率なクエリになります。インデックスの。大規模なデータセットでこの種の部分文字列検索を効率的に行う必要がある場合は、MySQL よりも特定の目的に適したものを使用することをお勧めします。

于 2013-01-04T01:06:40.153 に答える
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 つの列内の値の組み合わせを表す 1 つの列が作成されます。それぞれの出現回数をカウントします。

于 2013-01-04T00:58:39.683 に答える