200行の関数を持つアプリケーションを作成することはありません。これらの長い関数は、それぞれが明確に定義された単一の責任を持つ小さな関数に分解します。
なぜそのようなSQLを書くのですか?
関数を分解するのと同じように、クエリを分解します。これにより、より短く、簡単に、理解しやすく、テストしやすくなり、リファクタリングしやすくなります。また、手続き型コードの場合と同じように、それらの間に「シム」とそれらの周りの「ラッパー」を追加できます。
これどうやってやるの?それぞれの重要なことを行うことにより、クエリはビューになります。その後、作曲、あなたがより原始的な機能のうち、より複雑な機能を構成するのと同様に、これらの単純なビューのうち、より複雑なクエリを。
そして、すばらしいのは、ほとんどのビューの構成で、RDBMSからまったく同じパフォーマンスが得られることです。(あなたはしませんいくつかのために;?だから何時期尚早の最適化は諸悪の根源であるコードを正しくまず、。その後、最適化あなたがする必要がある場合。)
複数のビューを使用して複雑なクエリを分解する例を次に示します。
この例では、各ビューが変換を1つだけ追加するため、それぞれを独立してテストしてエラーを見つけることができ、テストは簡単です。
この例のベーステーブルは次のとおりです。
create table month_value(
eid int not null, month int, year int, value int );
このテーブルには、月と年の2つの列を使用して1つのデータム、つまり絶対月を表すため、欠陥があります。新しい計算列の仕様は次のとおりです。
これを線形変換として実行し、(年、月)と同じように並べ替え、(年、月)のタプルには値が1つだけあり、すべての値が連続するようにします。
create view cm_absolute_month as
select *, year * 12 + month as absolute_month from month_value;
これで、テストする必要があるのは仕様に固有です。つまり、タプル(年、月)は1つだけ(absolute_month)あり、(absolute_month)は連続しています。テストを書いてみましょう。
テストはselect
、次の構造を持つSQL クエリになります。テスト名とcaseステートメントが連結されています。テスト名は単なる任意の文字列です。case文は単なるcase when
テスト文then 'passed' else 'failed' end
です。
テスト文は、テストが合格するために真でなければならないSQL選択(サブクエリ)です。
これが最初のテストです。
--a select statement that catenates the test name and the case statement
select concat(
-- the test name
'For every (year, month) there is one and only one (absolute_month): ',
-- the case statement
case when
-- one or more subqueries
-- in this case, an expected value and an actual value
-- that must be equal for the test to pass
( select count(distinct year, month) from month_value)
--expected value,
= ( select count(distinct absolute_month) from cm_absolute_month)
-- actual value
-- the then and else branches of the case statement
then 'passed' else 'failed' end
-- close the concat function and terminate the query
);
-- test result.
そのクエリを実行すると、次の結果が生成されます。 For every (year, month) there is one and only one (absolute_month): passed
month_valueに十分なテストデータがある限り、このテストは機能します。
十分なテストデータのテストも追加できます。
select concat( 'Sufficient and sufficiently varied month_value test data: ',
case when
( select count(distinct year, month) from month_value) > 10
and ( select count(distinct year) from month_value) > 3
and ... more tests
then 'passed' else 'failed' end );
次に、連続しているかどうかをテストします。
select concat( '(absolute_month)s are consecutive: ',
case when ( select count(*) from cm_absolute_month a join cm_absolute_month b
on ( (a.month + 1 = b.month and a.year = b.year)
or (a.month = 12 and b.month = 1 and a.year + 1 = b.year) )
where a.absolute_month + 1 <> b.absolute_month ) = 0
then 'passed' else 'failed' end );
次に、クエリであるテストをファイルに入れ、そのスクリプトをデータベースに対して実行します。実際、データベースに対して実行するスクリプト(またはスクリプト、関連するビューごとに1つのファイルを推奨)にビュー定義を保存する場合、各ビューのテストを同じスクリプトに追加して、(re -)ビューを作成すると、ビューのテストも実行されます。そうすることで、ビューを再作成するときに回帰テストを受け、ビューの作成が本番環境に対して実行されると、ビューも本番環境でテストされます。