7

gendata2 つのテーブル&からデータを取得するために、次の SQL ステートメントを作成しましたTrainingMatrix

SELECT * FROM (SELECT DISTINCT ON ("TrainingMatrix".payroll, "TrainingName", "Institute")"gendata"."Employee Name","gendata"."Position", "gendata"."Department",  "TrainingMatrix".* 
FROM "TrainingMatrix" JOIN "gendata" ON "TrainingMatrix".payroll = "gendata".payroll 
ORDER  BY payroll, "TrainingName", "Institute" ,"TrainingDate" DESC NULLS LAST) AS foo;

正常に動作しますが、次の方法でレコードをさらにフィルタリングする必要があります。

WHERE "TrainingMatrix"."ExpiryDate" - current_date <= 0 
AND  EXTRACT(YEAR FROM  "TrainingMatrix"."ExpiryDate") = EXTRACT(YEAR FROM current_date);

したがって、元の SQL ステートメントは次のようになります。

SELECT * FROM (SELECT DISTINCT ON ("TrainingMatrix".payroll, "TrainingName", "Institute")"gendata"."Employee Name","gendata"."Position", "gendata"."Department",  "TrainingMatrix".* 
FROM "TrainingMatrix" JOIN "gendata" ON "TrainingMatrix".payroll = "gendata".payroll 
ORDER  BY payroll, "TrainingName", "Institute" ,"TrainingDate" DESC NULLS LAST) AS foo WHERE "TrainingMatrix"."ExpiryDate" - current_date <= 0 
AND  EXTRACT(YEAR FROM  "TrainingMatrix"."ExpiryDate") = EXTRACT(YEAR FROM current_date);

しかし、私はこのエラーが発生しました:

エラー: テーブル "TrainingMatrix" 行 3 の FROM 節エントリがありません: ...te" ,"TrainingDate" DESC NULLS LAST) AS foo WHERE "TrainingM...

私はPostgreSQLを使用しています。みんなにアドバイスはありますか?

4

2 に答える 2

9

@a_horseがすでに言ったこと100%。さらに、さらにいくつかのこと:

  • デバッグを試みる前に、人間が読みやすく理解しやすいようにクエリをフォーマットします。公開フォーラムに投稿する前はなおさらです。

  • 読みやすくするために、特に不幸な CaMeL ケースの名前には、テーブル エイリアスを使用してください。

  • クエリにテーブル定義または少なくともテーブル修飾列名を指定してください。これにより、解析する機会が得られます。当面の問題は、以下のクエリで既に修正されています。?.また、それに応じ て置き換えます。

    • t.. の別名"TrainingMatrix"
    • g.. の別名gendata

SELECT *
FROM  (
    SELECT DISTINCT ON (t.payroll, ?."TrainingName", ?."Institute")
           g."Employee Name", g."Position", g."Department",  t.* 
    FROM   "TrainingMatrix" t
    JOIN   gendata          g  ON g.payroll = t.payroll 
    ORDER  BY t.payroll, ?."TrainingName", ?."Institute"
         , ?."TrainingDate" DESC NULLS LAST
    ) AS foo
WHERE  foo."ExpiryDate" - current_date <= 0 
AND    EXTRACT(YEAR FROM  foo."ExpiryDate") = EXTRACT(YEAR FROM current_date);

しかし、もっとあります。

  • @a_horse が書いたように、常に二重引用符で囲まなければならない不正な識別子を使用するのは悪い考えです。しかし、スペース文字で囲まれた識別子はさらに悪い: "Employee Name". これは、自作の SQL インジェクションから一歩離れたところにあります。

  • 追加のフィルターの表現方法は、パフォーマンスに悪影響を及ぼします。

    WHERE  "ExpiryDate" - current_date <= 0 
    

    sargableではないため、単純なインデックスを使用できません。それはさておき、それは必要以上に高価でもあります。代わりに使用してください:

    WHERE "ExpiryDate" >= current_date
    

    2 番目の式も同様で、次のように書き換える必要があります。

    WHERE  "ExpiryDate" >= date_trunc('year', current_date)
    AND    "ExpiryDate"  < date_trunc('year', current_date) + interval '1 year'
    

    両方を組み合わせると、冗長な式を削除できます。

    WHERE  "ExpiryDate" >= current_date
    AND    "ExpiryDate"  < date_trunc('year', current_date) + interval '1 year'
    
  • あなたの質問はあいまいです。追加フィルタを前DISTINCTまたは後に適用しますか? 異なる結果。
    に 仮定すると、サブクエリは必要ありません。これにより、差し迫った問題の原因が取り除かれます。サブクエリに別のエイリアスはありません。 DISTINCT

すべて一緒に:

SELECT DISTINCT ON (t.payroll, "TrainingName", "Institute") 
       g."Employee Name", g."Position", g."Department", t.* 
FROM   "TrainingMatrix" t
JOIN   gendata          g USING (payroll)
WHERE  t."ExpiryDate" >= current_date
AND    t."ExpiryDate" <  date_trunc('year', current_date) + interval '1 year'
ORDER  BY t.payroll, "TrainingName", "Institute", "TrainingDate" DESC NULLS LAST
于 2013-11-14T23:34:29.670 に答える
6

実際のクエリを派生テーブル ( select .. from (...) as foo) にラップしたため、「テーブル」は呼び出されTrainingMatrixなくなりました。派生テーブルに使用するエイリアスを使用して参照する必要があります。

select *
from (
  ... you original query ..
) as foo
where foo."ExpiryDate" - current_date <= 0
and   extract(year from foo."ExpiryDate") = extract(year from current_date)

ところで:大文字と小文字を区別する名前を使用して引用符で囲まれた識別子を使用するのをやめることをお勧めします"ExpiryDate"。通常、価値がある以上の問題が発生します。

于 2013-11-14T11:15:13.783 に答える