2017-07-06 11 views
1

私はAccess 2010を使用してSQL Server上のいくつかのデータを操作しています。各エンティティは1つのIDを取得し、それに続く属性のリストを特定の最大または最小エントリなしで持つことができます。このデータセットを作成した人が持っていた解決策は、37種類の属性の列セットを作成することでした。各属性には4つの列があります(2つしか使用できません)。実際には、おそらく37個のアイテムを持つことを表す148個の列がありますが、グループ3または4を過ぎたほとんどの列はNULLです。値は一貫していますが、値は最初に最初の列グループに移動します。どの列もNULL値を持つとすぐに、それ以降のすべての列もNULLであるとみなすことができます。最初の列がNULLの場合、属性はありません。データはやや次のようになります。null値までテーブル列を反復する

| ID | Attr1 | Code1 | Attr2 | Code2 | Attr3 | Code3 | |----|-------|-------|--------|--------|--------|--------| | 1 | Foo | 2 | Bar | 1 | (null) | (null) | | 2 | Bar | 2 | (null) | (null) | (null) | (null) | | 3 | Bar | 1 | Foo | 1 | Bar | 2 |

その行がCODE1を持っている場合でも、誰かがコーデックス= 1(X任意の数であることを)望んでいる場合は、クエリが返すように、この上で照会するための最良の方法は、結果がどうなりますか= 1またはCode37 = 1である。

A.Mod1=1 
Or A.Mod2=1 
Or A.Mod3=1 
Or A.Mod4=1 
... 

をしかし、それは恐ろしい見え、鉄砲水と同じくらい乾燥している:私はこのような何かを考えました。おそらく私が行う属性とコードの両方を対象にしたいのであれば、特に恐ろしいことになります。私は、最初のヌル値の値を反復して戻す方法を考える方法を考えることができることを簡単に見てきましたが、私のドラフトはあまり意味を持たず、ひどく乱雑ですネストされた。

上記の本当に醜い方法を除いて、これらの問題を解決する方法についてのご意見はありますか?

+0

で以下のロジックを使用できるようになるあなたはパススルークエリを行うことができますか? COALESCEキーワードと逆の順序で列を使用して、列のリストの最初の非NULL値を取得します。 – Jeremy

+0

パススルーを行うことができます。私はそれをすぐに見てみましょう。 –

+0

さて、それは私が必要とするものに近づいています。これを実行したいステップの1つは、ヌルでないすべての値を返すことができるため、入力を省くことができることです。 また、特定の値を照合できるようにするため、「NOT NULL」が十分に意味がないため、結合のたびに式を書き出す必要があります。その後私は自分のORステートメントで始まったところに戻ります。 –

答えて

0

データをピボット解除する方法は2つあります。これを行うと、パラメータにwhere句を追加するだけで済みます。私。最初のクエリにwhere code = 1を追加するか、2番目のクエリにwhere codes = 1を追加するだけです。必要に応じてこのバックアップをピボットすることもできますが、これはトンを正規化します。あなたが言ったように、あなたは狂った長いCASEステートメントでこれを行うことができますが、それは乾燥しており、長くなります。

declare @table table(ID int, Attr1 varchar(16), Code1 varchar(16),Attr2 varchar(16), Code2 varchar(16), Attr3 varchar(16), Code3 varchar(16)) 
insert into @table 
values 
(1,'Foo',2,'Bar',1,NULL,NULL), 
(2,'Bar',2,NULL,NULL,NULL,NULL), 
(3,'Bar',1,'Foo',1,'Bar',2) 

select 
    t.ID, 
    c.Attribute, 
    c.Code 
from @table t 
cross apply (
      select Attr1, Code1 union all 
      select Attr2, Code2 union all 
      select Attr3, Code3 
      ) c (Attribute, Code) 
where 
    Attribute is not null 


select 
    ID, 
    Attributes, 
    Codes 
from(
    select ID, Attr1, Code1, Attr2, Code2, Attr3, Code3 
    from @table) main 
unpivot 
(Attributes for Attribute in (Attr1, Attr2, Attr3)) attr 
unpivot 
(Codes for Code in (Code1, Code2, Code3)) cod 
where 
    right(Attribute,1) = right(Code,1) 

パフォーマンス面では、それはおそらくより高速なデータアンピボットませになりますが、オプティマイザは、単純なブールcomparisions

declare @Code int = 2 
declare @Attr varchar(64) = null 

select 
    t.* 
from @table t 
where 
    (Code1 = @Code or 
    Code2 = @Code or 
    Code3 = @Code or 
    @Code is null) 
    and 
    (Attr1 = @Attr or 
     Attr2 = @Attr or 
     Attr3 = @Attr or 
     @Attr is null) 
+0

私はおおよそどこでこれを行うのか理解しており、非常に役に立ちます。実行が終了するまでは、これはOR文を組み合わせた37の条件よりも優れていますか?私はこのような複雑な操作をすでに大きなデータベースで実行すると、私のパフォーマンスに大きく影響することを恐れています。私のコードは大部分がバックグラウンドで実行され、ユーザー入力はコードや属性が検索されることを定義するので、エンドユーザーのパフォーマンスが最優先です。残念なことに、このテーブルは毎月更新されるため、テーブルのローカル修正コピーをダウンロードすることも目的を破ります。 –

+0

あなたの構造や索引などによってはどちらが良いかを判断することは不可能です。本当に唯一の方法は、テストシステムでも、オフタイムでも、何時でもテストすることです。あなたがそれを実行し、それが数秒(またはあなたのしきい値が何時まで)よりも長くかかる場合は、単にクエリを終了し、他の方法で試してみてください。正直言って、大規模なブーリアンステートメントはおそらく最も速くなりますが、クエリーは長く実行される可能性が高くなります。私は底にそれを更新します。 – scsimon

+0

@AndrewMcPheronが答えを更新しました。オプティマイザは、最も確実に最後のクエリを最も速く見つけることができます。パラメータのいずれか、両方、またはどちらもnullに設定することはできません。 – scsimon

関連する問題