複雑なSQLクエリを記述しやすくするにはどうすればよいですか?[閉まっている]


42

私は、多くの(少なくとも3-4)テーブルにわたる結合といくつかのネストされた条件を含む複雑なSQLクエリを書くことは非常に難しいと思っています。書くように求められているクエリは、いくつかの文で簡単に説明できますが、完了するためには、途方もない量のコードが必要になる場合があります。私はこれらのクエリを書くために一時的なビューを頻繁に使用していることに気付いています。これらの複雑なクエリを簡単にするために使用できるヒントを教えてください。より具体的には、これらのクエリを、実際にSQLコードを記述するために使用する必要があるステップに分割するにはどうすればよいですか?

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

技術的な詳細:

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

一時ビューは、SQLパーサーにヒントを与えるのが非常に難しい(明示的な複雑なインデックスのような)テーブルに対して操作を実行できるため、実際には非常に便利です。

個人的には、GUI(LibreOffice Baseの「デザインビューでクエリを作成」またはOffice Accessの「作成」>「クエリデザイン」など)を使用してチートし、それが生成するSQLを表示する方が簡単です。GUIデザイナーによって指定されたSQLを変更する必要がある場合もありますが、それは良い出発点を与えます
-kurdtpage

回答:


49

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

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

LEFT参加シナリオについて考えます -先月からすべての従業員と給与を選択します。先月給料をもらえなかったらどうしますか?

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

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

集計の混合レベルに注意してください:同じ結果セットに月、四半期、および年初来の値を入れる必要がある場合、異なる値でグループ化されたクエリでそれらを個別に計算する必要があります。

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

複雑な/入れ子になった数式 -一貫してインデントするようにし、複数行を使用することを恐れないでください。「CASE WHEN CASE WHEN CASE WHEN」は、あなたを夢中にさせます。これらを熟考するために時間をかけてください。最後に複雑な計算を保存します。最初に選択された正しいレコードを取得します。次に、正しい値で作業していることを知っている複雑な数式を攻撃します。数式で使用されている値を確認すると、NULL値を考慮しなければならない領域とゼロ除算エラーを処理する領域を見つけるのに役立ちます。

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


1
本当に素晴らしいもの。LEFT結合を探し、複雑なクエリをより小さく管理しやすいクエリに分割し、それらを結合することに関するジェフのポイントを再度強調したいと思います。私は大規模なデータベースで大規模なクエリをほぼ毎日作成していますが、特にこれらの2つのことは常に発生します。各ステップで表示されると予想されるデータを確実に取得するために、できるだけ早くクエリとサブクエリを常に実行してください。
CodexArcanum

@CodexArcanum-ビッグデータでクエリを実行する場合、TOPを使用しても害はありません;)
JeffO

あなたの提案のすべての声明に同意します
アレッサンドロロッシ

28
  1. インデントは、まだ実行していない場合、最初に行うことです。単純なクエリでも有用であるだけでなく、結合よりもやや複雑なクエリに関しては非常に重要select top 1 [ColumnName] from [TableName]です。

  2. 適切にインデントされると、必要に応じてクエリ自体にコメント追加することを禁止しません。それらを使いすぎないでください。コードが十分に明確な場合、コメントを追加するとコードの明瞭さが損なわれます。ただし、クエリの明示的でない部分については引き続き歓迎します。

    長いクエリ(コメント付きのクエリを含む)は、アプリケーションサーバーとデータベースサーバー間の帯域幅の使用量が大きくなることに注意してください。また、1秒あたりのリクエスト数が膨大で、並外れたパフォーマンスとリソース使用量を必要とするGoogleスケールの製品で作業している場合を除き、コメントによって追加されたサイズはパフォーマンスに関して何も変わらない可能性があります。

  3. テーブル、列などに同じスタイルを適用すると、読みやすくなります。レガシーデータベーステーブルを持っている場合はPRODUCTusersUSERS_ObsoleteDONT_USEPR_SHIPMENTSHRhbYd_UU、誰かが非常に間違って何かをやっています。

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

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

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


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

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


9

ここでは少し暗闇でのショットですが、一時的なビューを大量に作成している場合、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

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

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

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

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


3
私はSQLの専門家であり、このインデントは本当に嫌いです。見た目は良いかもしれませんが、「私の意見では」まったく役に立ちません。2つの理由:左外部結合がメインクエリの一部であるか、サブクエリの一部であるかが明確にわからないため、コードビューティファイヤが必要です。また、すべてのテキストを再ビューティ化する必要がある数行を追加する場合はいつでも。TABSだけが必要なプランのインデントは、はるかに柔軟です。私はあなたの答えに反対票を投じませんでしたが、このスタイルを使用している人を本当に落胆させます...特に彼らが私の助けを必要とするとき。
アレッサンドロロッシ

7

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


1
cteを使用する場合、クエリは次のクエリが実行されるまでしか持続しないことに注意してください。したがって、複数のクエリでcteを使用している場合は、一時テーブルを使用する方がパフォーマンスが良い場合があります。
レイチェル

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

1

他の何かと同様に、問題を管理可能な部分に分解する必要があります。

ところで、それが本当に複雑な問題を解決する方法です。

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.