2012-11-26 18 views
7

私は、各行に整数値が含まれている7列のmysqlテーブルを持っています。MySQLのMySQLの順列のテーブル

私はユーザーから値を受け取るシンプルなサイトを持っていて、ユーザーが送信した値がテーブル内のいずれかの行に似ているかどうかを確認する必要があります。

したがって、ユーザーは、入力として1 2 3 4 5 6 7

私のテーブルのどの行も注文なしでそれに似ているかどうか調べる必要があります。だから1 2 3 4 5 6 7 = 7 6 5 4 3 2 1など。テーブルmyには40,000以上のデータ行が含まれています。

少なくとも56または7という数字を共有しているかどうかを確認する必要があります。

これは、すべての可能な組み合わせを見つけるために順列を使用することを意味します。しかし、そのような問題のための最良のアプローチは何ですか?

  1. ユーザーからの入力を取り、最初の行、2番目の行などすべての順列と一致し、見つかった場合は報告しますか?逆に、テーブルから行を取得し、すべての順列を取得し、ユーザーの入力との一致を行うか?

  2. 非常に多くの順列でそのような大きなテーブルを通過するときのメモリとCPU使用率はどうですか?

ありがとうございました! Souciance

+0

ユーザー入力とデータを同じ昇順に並べて比較するのが最善の方法です。 –

答えて

1

軽い方法では、データベースにフィールドを追加することができます。これは、7つのフィールドすべてを数値順に並べたものです。

例えば、データベース内のデータが2 4 7 6 5 1 3の場合、結合フィールドは1234567

となります。比較すると、ユーザー応答を数値でソートし、データベースの結合フィールドと比較します。あなたが一致する数字の最小数は、クエリ

を明るくすることを、する必要があります知っている場合は

あなたは何をしているかに応じて、この

select * from table where combination like '12%' or combination like '123%' 

のようなクエリを書くことができ彼らが書いたものとデータベースの内容との類似性を調べる。私はあなたが本当に効率的にこのような問題にクエリを構築することはできません怖いhttp://php.net/manual/en/function.levenshtein.php

$result = levenshtein($input,$combination); 
+0

私はこのアイデアが好きです、良いアプローチのように聞こえるよ! –

0

:あなたは、レーベンシュタインPHP関数を使用することができます。

あなたは次のようWHERE句を構築することがあります。

(`1` IN ARRAY(1,2,3,4,5,6,7) 
    AND `2` IN ARRAY(1,2,3,4,5,6,7) 
    AND `3` IN ARRAY(1,2,3,4,5,6,7) 
    AND `4` IN ARRAY(1,2,3,4,5,6,7) 
    AND `5` IN ARRAY(1,2,3,4,5,6,7)) 
OR 
(`1` IN ARRAY(1,2,3,4,5,6,7) 
    AND `2` IN ARRAY(1,2,3,4,5,6,7) 
    AND `3` IN ARRAY(1,2,3,4,5,6,7) 
    AND `4` IN ARRAY(1,2,3,4,5,6,7) 
    AND `6` IN ARRAY(1,2,3,4,5,6,7)) 
-- Each combination 

しかし、それは条件の地獄だろう。コラム1は情報が含まれている場合

チェックのファースト:次に

IF(`1` IN ARRAY(1,2,3,4,5,6,7), 1, 0) 

合計一方、あなたは、の組み合わせを使用してみてくださいすべてのデータ:

SELECT (
    IF(`1` IN ARRAY(1,2,3,4,5,6,7), 1, 0) + 
    IF(`2` IN ARRAY(1,2,3,4,5,6,7), 1, 0) + 
    IF(`3` IN ARRAY(1,2,3,4,5,6,7), 1, 0) + 
    IF(`4` IN ARRAY(1,2,3,4,5,6,7), 1, 0) + 
    IF(`5` IN ARRAY(1,2,3,4,5,6,7), 1, 0) + 
    IF(`6` IN ARRAY(1,2,3,4,5,6,7), 1, 0) + 
    IF(`7` IN ARRAY(1,2,3,4,5,6,7), 1, 0) 
) AS `matches_cnt` 
FROM t1 
HAVING `matches_cnt` >= 5 

これはすべての行を繰り返すため、条件はかなり複雑です(したがってベッドのパフォーマンス)。

あなたはまた、例えば、バイナリ文字列で値を交換してみて:

1,2,7 = 01000011 

そして点検記録とデータベースの間Hamming distanceを計算するが、これが唯一の条件の複雑さを減少させますが、トラフすべてのレコードを反復処理する必要があります。同じままです。使用MySQLで

実装:これは単なる完全正規化スキーマで

SELECT (
    $MAX_NUMBER$ - BIT_COUNT(XOR(`binary_representation`, $DATA_FROM_USER$)) 
) AS `matches_cnt` 
3

をすることにより、第1の部分を置換しますクエリ

だとしてPKを使用してテーブルを想定してみましょう:この時点では

create table T1 
(pk char (1), a1 int, a2 int, a3 int, a4 int, a5 int, a6 int, a7 int); 

insert into T1 values 
('a',1,2,3,4,5,6,7), 
('b',2,3,4,5,6,7,8), 
('z',10,11,12,13,14,15,16); 

、我々は、データを正規化することができます

前のクエリで
select 
    pk, 
    case a 
    when 1 then a1 
    when 2 then a2 
    when 3 then a3 
    when 4 then a4 
    when 5 then a5 
    when 6 then a6 
    when 7 then a7 
    end 
    as v 
from T1 
cross join 
    (select 1 as a from dual union all 
    select 2 as a from dual union all 
    select 3 as a from dual union all 
    select 4 as a from dual union all 
    select 5 as a from dual union all 
    select 6 as a from dual union all 
    select 7 as a from dual) T2 

、であなたの要件に合わせやすいです単一持つ:

select pk 
from 
(
select 
    pk, 
    case a 
    when 1 then a1 
    when 2 then a2 
    when 3 then a3 
    when 4 then a4 
    when 5 then a5 
    when 6 then a6 
    when 7 then a7 
    end 
    as v 
from T1 
cross join 
    (select 1 as a from dual union all 
    select 2 as a from dual union all 
    select 3 as a from dual union all 
    select 4 as a from dual union all 
    select 5 as a from dual union all 
    select 6 as a from dual union all 
    select 7 as a from dual) T2 
) T 
where 
    T.v in (4,5,6,7,8,9,10) 
group by pk 
having           <-- The Having 
    count(pk) > 4 

Results

| PK | 
------ 
| b | 
+0

うーん..解決策がありがとうと思っていませんでした。 –