[解決済み] SQLクエリのテストに最適な方法 [終了しました]。
質問
複雑な SQL クエリーがエラーで出力され続けるという問題に遭遇しました。基本的に、これは間違った顧客にメールを送ったり、そのような他の「問題」のような結果になります。
このような SQL クエリを作成することについて、みなさんはどのような経験をお持ちでしょうか。私たちは 1 週間おきに新しいコホート データを作成しています。
そこで、私の考えとそれに対する制限をいくつか紹介します。
-
テストデータの作成 これは、私たちがすべての正しいデータを持っていることを証明しますが、実稼働時の異常の除外を強制するものではありません。 これは、今日では間違っていると考えられるが、10 年前には正しかったかもしれないデータのことで、文書化されていなかったため、データが抽出された後に初めて知ることになります。
-
ベン図やデータマップを作成する これはクエリの設計をテストする堅実な方法のように見えますが、しかし実装が正しいことを保証するものではありません。 これは、開発者が前もって計画を立て、書くときに何が起こっているかを考えるようにします。
私の問題に与えてくれるどんな意見にも感謝します。
どのように解決するのですか?
あなたは200行の長い関数でアプリケーションを書くことはないでしょう。これらの長い関数を、それぞれ明確に定義された1つの責任を持つ、より小さな関数に分解するのです。
なぜそのような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;
つまり、どんなタプル(年、月)でも、(absolute_month)は一つしかなく、(absolute_month)は連続であるということです。いくつかのテストを書きましょう。
私たちのテストはSQLの
select
クエリで、テスト名と case 文が一緒になった構造になっています。テスト名は単なる任意の文字列です。case 文は単に
case when
テスト文
then 'passed' else 'failed' end
.
テスト文は、テストに合格するために真でなければならないSQLのselect(サブクエリ)だけである。
これが最初のテストです。
--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 );
では、テスト(単なるクエリ)をファイルにまとめ、そのスクリプトをデータベースに対して実行してみましょう。実際、データベースに対して実行されるスクリプト (あるいはスクリプト。関連するビューごとにひとつのファイルを推奨します) にビューの定義を格納すれば、各ビューのためのテストを と同じです。 スクリプトに追加することで、ビューを (再) 作成する際にそのビューのテストも実行することができます。この方法では、ビューを再作成するときにリグレッション テストを取得し、ビューの作成が本番環境で実行されるとき、ビューも本番環境でテストされます。
関連
-
[解決済み] Oracle Trigger ORA-04098: トリガーが無効で、再バリデーションに失敗しました。
-
[解決済み] SQL ServerでSELECTからUPDATEする方法とは?
-
[解決済み] プライベートメソッド、フィールド、インナークラスを持つクラスをテストするにはどうすればよいですか?
-
[解決済み] PHPでSQLインジェクションを防ぐにはどうしたらいいですか?
-
[解決済み] MySQLでコマンドラインを使用してSQLファイルをインポートするにはどうすればよいですか?
-
[解決済み] SQLテーブルで重複する値を検索する
-
[解決済み] SQL Server で複数行のテキストを 1 つのテキスト文字列に連結する方法
-
[解決済み] SQL Server - 挿入された行のIDを取得するための最良の方法は?
-
[解決済み] フラットテーブルをツリーにパースする最も効率的/エレガントな方法は何ですか?
-
[解決済み】SQL Serverで既存のテーブルにデフォルト値を持つカラムを追加する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
windows mysql prompt access denied for user ''@'localhost' to database.
-
[解決済み] ストアドプロシージャ 'dbo.aspnet_CheckSchemaVersion' が見つかりませんでした。
-
[解決済み] ATTACHで開いたSQLiteデータベースファイルのテーブルを一覧表示するにはどうすればよいですか?
-
[解決済み] SQL Serverにおける関数とストアドプロシージャの比較
-
[解決済み] MySQLでFULL OUTER JOINを行うにはどうすればよいですか?
-
[解決済み] 各グループの上位1行を取得
-
[解決済み] mysqldumpで特定のテーブルをスキップする
-
[解決済み] SQLでランダムな行を要求する方法は?
-
[解決済み] 複数の列に対してSELECT DISTINCTする方法(またはできる方法)は?
-
[解決済み] SQL ServerでGROUP BYを使って文字列を連結する方法とは?