2012-04-20 5 views
1

問題の文は以下の通りです:このSQLコードは、置換を排除するためにどのように改善できますか?

-One構造を持つテーブルのINITを持っている

-Iは、表に「タブ」テーブルのINITのすべての行を挿入したい
(number1 INT not null, number2 INT not null, ..., number7 INT not null) 

が、私にはありません に2つの行を 'tab'に入れて、一方がもう一方の順列になるようにします。したがって、たとえば、 (1,2,3,7,19,21,6)および(19,2,3,7,1,21,6)がINITの行である場合は、1つだけ それらは「タブ」に終わらなければならない。それらのどれが「タブ」で終わるかは問題ではありません。

- 次のコードは次のとおりです。補助テーブル 'aux'を INITと同じ構造にしています。私はテーブルINITのすべての行を繰り返し、各行に対して をINITで並べ替えます。そのため、(1,2,3,7,19,21,6)が INITの行であれば、それを並べ替え(1,2,3,6,7,19,21)、それが 'aux'に入っているかどうか確認してください。 の場合は次の行に進みます。それ以外の場合は、「タブ」に(1,2,3,7,19,21,6)を挿入します。

この手順は、300,000行のINITテーブルに対して実行しました。実行には7時間以上かかると推定しています( )。この手順の実行時間を改善するにはどうすればよいですか?

DECLARE done BOOLEAN default 0; 
DECLARE n1,n2,n3,n4,n5,n6,n7 INT; 
DECLARE o1,o2,o3,o4,o5,o6,o7 INT; 
DECLARE my_cursor cursor FOR select * from INIT; 
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;  
OPEN my_cursor; 

drop table if exists aux; 
create table aux(
    number1 INT not null, 
    number2 INT not null, 
    number3 INT not null, 
    number4 INT not null, 
    number5 INT not null, 
    number6 INT not null, 
    number7 INT not null, 
); 
create table temp(number INT); 

REPEAT 
    truncate table temp; 

    FETCH my_cursor INTO n1,n2,n3,n4,n5,n6,n7; 
     INSERT INTO temp values(n1); 
     INSERT INTO temp values(n2);  
     INSERT INTO temp values(n3); 
     INSERT INTO temp values(n4); 
     INSERT INTO temp values(n5); 
     INSERT INTO temp values(n6); 
     INSERT INTO temp values(n7); 
     BEGIN 
      DECLARE done2 BOOLEAN default 0; 
      DECLARE my_cursor2 cursor FOR select * from temp order by number; 
      OPEN my_cursor2; 
      FETCH my_cursor2 INTO o1; 
      FETCH my_cursor2 INTO o2; 
      FETCH my_cursor2 INTO o3; 
      FETCH my_cursor2 INTO o4; 
      FETCH my_cursor2 INTO o5; 
      FETCH my_cursor2 INTO o6; 
      FETCH my_cursor2 INTO o7; 

      IF NOT EXISTS (SELECT * FROM aux where number1=o1 AND number2=o2 AND number3=o3 
          AND number4=o4 AND number5 = o5 AND number6 = o6 AND number7=o7) 
      THEN 
       INSERT INTO tab VALUES (n1,n2,n3,n4,n5,n6,n7); 
      END IF; 
      CLOSE my_cursor2; 
     END; 
UNTIL done END REPEAT; 
CLOSE my_cursor; 

編集:INITの -In各行を、すべての整数が異なっています。 - INITの主キーは(数字1、数字2、...、数字7)

+0

(どちらかそれを疑うない)ボヘミアンのソリューションが動作する方法をよく知ってはいけません、質問は...いずれかの数字を1行ごとに繰り返すことができますか? – DRapp

+0

INITテーブルに主キーがありますか? –

+0

私のメッセージを編集しました。はい、INITテーブルにはプライマリキー(すべてのカラム)があり、1行につき番号を繰り返すことはできません。 – user1261701

答えて

1

あなたはすべての行に重いクエリを実行しています...良いアプローチではありません。

代わりに、あなたはせずに仕事がを成し遂げるためにストアドプロシージャ一部のデータベースカンフーを使用することができます。

insert into tab 
select number1, number2, number3, number4, number5, number6, number7 from (
    select number1, number2, number3, number4, number5, number6, number7, 
    group_concat(number order by number) as sig from (
     select number1, number2, number3, number4, number5, number6, number7, number1 as number 
     union all select number1, number2, number3, number4, number5, number6, number7, number2 
     union all select number1, number2, number3, number4, number5, number6, number7, number3 
     union all select number1, number2, number3, number4, number5, number6, number7, number4 
     union all select number1, number2, number3, number4, number5, number6, number7, number5 
     union all select number1, number2, number3, number4, number5, number6, number7, number6 
     union all select number1, number2, number3, number4, number5, number6, number7, number7) a 
) group by sig) b 

をここに関与する重要なトリックがある:

  • 内側の選択が可能にgroup_concat標準的な順序で数をグループ化して組み合わせを比較できるようにするには
  • group_concatで注文すると一意の記号MySQLで凝集することなくgroup byを使用して数字
  • ためatureでは、各グループごとにカラム値

ため最初行がところで、正しい用語は、組み合わせない順列

ある与えます

また、私はこれをテストしていないので、ブラケットなどが間違って配置されている可能性がありますが、「基本的に」動作するはずです。

0

Mysqlism、GROUP_CONCATを使用して比較します

create table p -- data source 
(
    grp int auto_increment primary key, n1 int, n2 int, n3 int, n4 int, n5 int, n6 int, n7 int 
); 


insert into p(n1,n2,n3,n4,n5,n6,n7) 
select 1,2,3,7,19,21,6 union 
select 19,2,3,7,1,21,6 union 
select 20,2,3,7,1,21,6; 


create table g -- staging table 
(
    grp int, 
    n int 
); 

insert into g(grp, n) 
select grp, n 
from 
(
    select grp, n1 as n from p 
    union all 
    select grp, n2 from p 
    union all 
    select grp, n3 from p 
    union all 
    select grp, n4 from p 
    union all 
    select grp, n5 from p 
    union all 
    select grp, n6 from p 
    union all 
    select grp, n7 from p 
) as x 

ユニーク抽出:

select grp, n1, n2, n3, n4, n5, n6, n7 
from p 
where grp in 
(
select min(grp) as first_elem -- select only one among duplicates 
from 
( 
    select grp, group_concat(n order by n) as comb 
    from g 
    group by grp 
) as x 
group by comb 
); 

基本的には、比較ロジックを容易にするために、いくつかのMySqlismを使用し、その後、数字を並べ替えるので、彼らは、組み合わせ、比較のために、より適しているが、すなわちGROUP_CONCAT

ライブテストを使用します。http://sqlfiddle.com/#!2/7b61f/1

+0

'union'が重複を取り除いてしまうので、うまくいきません。( – Bohemian

+0

重複を保持するために落ち込まず、' UNION'を 'UNION ALL'に変更してください;-) –

関連する問題