web-dev-qa-db-ja.com

複雑なSQLクエリを作成しやすくするにはどうすればよいですか?

多くの(少なくとも3〜4)テーブルの結合と、いくつかのネストされた条件を含む複雑なSQLクエリを作成するのは非常に困難です。私が書くように求められているクエリは、数文で簡単に説明できますが、完了するには不正な量のコードが必要になる場合があります。私は、一時的なビューを使用してこれらのクエリを記述することがよくありますが、これは少し松葉杖のように見えます。これらの複雑なクエリを簡単にするために使用できるヒントを教えてください。具体的には、これらのクエリを実際にSQLコードを作成するために使用する必要がある手順に分解するにはどうすればよいですか?

私が書くように求められているSQLはデータベースコースの宿題の一部であるため、私のために機能するソフトウェアは必要ありません。コードを実際に理解したいので注意してください。私は書いています。

より技術的な詳細:

  • データベースは、ローカルマシンで実行されているPostgreSQLサーバーでホストされています。
  • データベースは非常に小さく、テーブルは7つ以下で、最大のテーブルの行数は約50未満です。
  • SQLクエリは、LibreOffice Baseを介してサーバーにそのまま渡されます。
42
bwDraco

私はこれのほとんどを「正しい」答えを得ようとすることに基づいているので、いくつかのパフォーマンスの問題があることに気付くかもしれません。不正なクエリを高速化しても意味がありません。

テーブルの関係を理解する-ほとんどは1対多です。 「多くの」テーブルを知っている。結合に必要なフィールドを特定します。

左の参加シナリオについて考えてください-先月からすべての従業員とその給与を選択します。彼らが先月給与を受け取っていない場合はどうなりますか?

結果セットを確認する: 1)スプレッドシートで、クエリに対して少なくとも1つの正しいレコードを手動で入力します。 2)返されるレコードの数を特定するのに十分なほど単純な形式でクエリを記述します。これらの両方を使用してクエリをテストし、新しいテーブルを結合しても結果が変更されないことを確認します。

クエリを管理可能な部分に分割する-一度にすべてを記述する必要はありません。複雑なクエリは、単純なクエリのコレクションである場合があります。

混合レベルの集計に注意:月別、四半期別、年初来の値を同じ結果セットに含める必要がある場合は、異なる値でグループ化されたクエリで個別に計算する必要があります。

NIONのタイミングを知るサブグループを独自の選択ステートメントに分割する方が簡単な場合があります。マネージャーと他の従業員が混在するテーブルがあり、各列でこれらのグループのいずれかのメンバーシップに基づいてCaseステートメントを実行する必要がある場合、ManagerクエリとEmployeeクエリへのユニオンを作成する方が簡単な場合があります。それぞれに独自のロジックが含まれます。異なるテーブルのアイテムを異なる行に含める必要があるのは明らかな使用法です。

コンプレックス/ネストされた数式-一貫してインデントし、複数行を使用することを恐れないようにしてください。 「CASE WHEN CASE WHEN CASE WHEN」はあなたをナッツに駆り立てます。時間をかけてこれらをじっくりと考えてください。最後に複雑な計算を保存します。最初に正しいレコードを選択してください。次に、正しい値で作業していることを知っている複雑な数式を攻撃します。数式で使用されている値を確認すると、NULL値を考慮する必要がある領域と、ゼロ除算エラーを処理する領域を見つけるのに役立ちます。

新しいテーブルを追加するときに頻繁にテストして、目的の結果セットが引き続き得られ、どの結合または句が原因であるかを確認します。

49
JeffO
  1. インデントまだ実行していない場合は、最初に実行する必要があります。単純なクエリでも便利であるだけでなく、結合やクエリが_select top 1 [ColumnName] from [TableName]_よりも少し複雑になる場合にも重要です。

  2. 適切にインデントされると、クエリ自体の内部でコメントを追加することを禁じるものはありません。それらを使いすぎないでください。コードが十分に明示的である場合、コメントの追加はコードの明確さを損なうだけです。しかし、クエリのそれほど明確でない部分については、まだ歓迎されています。

    クエリが長い(コメント付きのクエリを含む)と、アプリケーションサーバーとデータベースサーバー間の帯域幅の使用量が増えることに注意してください。また、1秒あたりのリクエスト数が非常に多く、並外れたパフォーマンスとリソースの使用を必要とするGoogle規模の製品で作業しているのでない限り、コメントによって追加されたサイズによってパフォーマンスが変わることはありません。

  3. テーブル、列などに同じスタイルを適用するは、読みやすさも大幅に向上します。レガシーデータベースにテーブルPRODUCTusers、_USERS_ObsoleteDONT_USE_、_PR_SHIPMENTS_、および_HRhbYd_UU_がある場合、誰かが非常に悪いことをしています。

  4. クエリに対して同じスタイルを適用するも重要です。たとえば、Microsoft SQL Serverのクエリを作成していて、TableNameの代わりに_[TableName]_を使用することに決めた場合は、それに固執します。 selectの後に改行する場合は、クエリの半分だけではなく、すべてのクエリで実行してください。

  5. _*_を使用しないでください(Microsoft SQL Serverのif exists(select * from [TableName] where ...)のように)強い理由がない限り。 _*_は、一部のデータベース(ほとんどではない)でパフォーマンスに悪影響を与えるだけでなく、クエリを使用する開発者にとっても役に立ちません。同様に、開発者は名前ではなく、インデックスではなく値にアクセスする必要があります。

  6. 最後に、selectの場合、viewを指定しても問題はありません。それ以外の場合は、プロジェクトと作業している人¹によっては、ストアドプロシージャも使用できます²。


¹一部の人々はストアドプロシージャを嫌います。他の人は、いくつかの理由で(少なくとも完全に有効ですが)理由でそれらを好きではありません。

²同僚、他の生徒、教師など.

28

ここでは少し暗闇の中ですが、多くの一時的なビューを作成している場合、おそらくSQLステートメントにテーブルを配置できるほとんどの場所で、そのテーブルをクエリで置き換えることができることにまだ気付いていません。

したがって、テーブルAを一時ビューBに結合するのではなく、一時ビューBとして使用していたクエリにテーブルAを結合できます。次に例を示します。

    SELECT A.Col1, A.Col2, B.Col1,B.Col2
      FROM (SELECT RealTableZ.Col1, RealTableY.Col2, RealTableY.ID as ID
              FROM RealTableZ 
   LEFT OUTER JOIN RealTableY
                ON RealTableZ.ForeignKeyY=RealTableY.ID
             WHERE RealTableY.Col11>14
            ) As B
        INNER JOIN A
                ON A.ForeignKeyY=B.ID

この例は無意味ですが、構文を説明する必要があります。

「特別」ではない(インデックス付き、パーティション化されていない)ビューの場合、ビューを使用した場合と同じクエリプランになります。

記述を簡単にする限り、クエリ全体を書き出す前に、各部分を検証して、期待どおりの結果が得られることを確認できます。

これがあなたにとって古い帽子であるならば、私の謝罪。

9
psr

一時的なビューの代わりに、 WITH句 を使用します。これにより、大きなクエリをより読みやすい小さな部分に分割することがはるかに簡単になります。

7
user281377
  1. まだ慣れていない場合は、集合論に慣れてください。 SQLは集合論に基づいており、集合について理解を深めることで、SQLのしくみについて理解を深めることができます。
  2. より多くのSQlを練習します。SQLを学習しているだけで、すべてを行う方法を理解するのに時間がかかる場合、何かが実際に理解するまでに時間がかかる場合があります。結合は、それらを使用すればするほど、それを上手く利用できるようになる良い例です。
  3. クエリを実行するテーブルが適切に設計されていることを確認してください
  4. 複数の異なる方法で調整する必要がある共通のセットがある場合は特に、選択したクエリでビューを使用することを恐れないでください
3
Ryathal

他と同様に、問題を扱いやすい部分に分解したいとします。

本当にISところで、複雑な問題をどのように解決するか。

したがって、サブクエリをチェックアウトして、外部クエリを実行する前に、サブクエリが本当に必要なものを返すことを確認したいとします。結合している各テーブルの最小限の結合を試して、実際に適切に検討していることがわかるようにする必要があります。そういうもの。すべてを入力して、1回の打ち込みで必要なものを正確に取得することは、非現実的です。

SQLステートメントは、ある程度の複雑さに達すると、基本的にそれ自体が小さなプログラムになります。データがどのように組み合わされ、選択され、フィルタリングされ、出力されるかを本当に理解することは大きな違いを生みます。

1
Dan Ray