web-dev-qa-db-ja.com

MAX()およびMAX()OVER PARTITION BYはTeradata Queryでエラー3504を生成します

各コースコードの最後に完了したコースの日付と、各従業員の全体として最後に完了したコースコードを含む結果テーブルを作成しようとしています。以下は私のクエリです:

SELECT employee_number,
       MAX(course_completion_date) 
           OVER (PARTITION BY course_code) AS max_course_date,
       MAX(course_completion_date) AS max_date
FROM employee_course_completion
WHERE course_code IN ('M910303', 'M91301R', 'M91301P')
GROUP BY employee_number

このクエリは、次のエラーを生成します。

3504 : Selected non-aggregate values must be part of the associated group

MAX()OVER(PARTITION BY ...)行を削除すると、クエリは正常に実行されるので、その行に問題を切り分けましたが、これらのフォーラムやインターネットを検索した後、何が表示されているのかわかりませんm間違っている。誰か助けてもらえますか?

8
dneaster3

Poniesがコメントで述べているように、OLAP関数と集約関数を混在させることはできません。

おそらく、各従業員の最終完了日を取得し、それを3つの対象コースのそれぞれの最終完了日を含むデータセットに結合する方が簡単かもしれません。

これはテストされていないアイデアであり、うまくいけばあなたは正しい道に進むはずです:

  SELECT employee_number,
         course_code,
         MAX(course_completion_date) AS max_date,
         lcc.LAST_COURSE_COMPLETED
    FROM employee_course_completion ecc
         LEFT JOIN (
             SELECT employee_number,
                    MAX(course_completion_date) AS LAST_COURSE_COMPLETED
               FROM employee_course_completion
              WHERE course_code IN ('M910303', 'M91301R', 'M91301P')
         ) lcc
         ON lcc.employee_number = ecc.employee_number
   WHERE course_code IN ('M910303', 'M91301R', 'M91301P')
GROUP BY employee_number, course_code, lcc.LAST_COURSE_COMPLETED

論理的にOLAP関数はGROUP BY/HAVINGの後に計算されるため、GROUP BYの列または集計関数を使用した列にのみアクセスできます。以下は奇妙に見えますが、標準SQLです。

SELECT employee_number,
       MAX(MAX(course_completion_date)) 
           OVER (PARTITION BY course_code) AS max_course_date,
       MAX(course_completion_date) AS max_date
FROM employee_course_completion
WHERE course_code IN ('M910303', 'M91301R', 'M91301P')
GROUP BY employee_number, course_code

Teradataではエイリアスの再利用が許可されているため、これも機能します。

SELECT employee_number,
       MAX(max_date) 
           OVER (PARTITION BY course_code) AS max_course_date,
       MAX(course_completion_date) AS max_date
FROM employee_course_completion
WHERE course_code IN ('M910303', 'M91301R', 'M91301P')
GROUP BY employee_number, course_code
3
dnoeth

これは非常に古い質問であることは知っていますが、他の誰かから似たような質問を受けました。

TeraDataを持っていませんが、次のことはできませんか?

_SELECT employee_number,
       course_code,
       MAX(course_completion_date)                                     AS max_course_date,
       MAX(course_completion_date) OVER (PARTITION BY employee_number) AS max_date
FROM employee_course_completion
WHERE course_code IN ('M910303', 'M91301R', 'M91301P')
GROUP BY employee_number, course_code
_

_GROUP BY_では、従業員ごとにコースごとに1行が確保されます。つまり、_max_course_date_を取得するには、ストレートMAX()が必要なだけです。

あなたの_GROUP BY_が従業員ごとに1つの行を与えるだけで、MAX() OVER()がその1つの行に対して複数の結果を与えようとする前は(コースごとに1つ)でした。

代わりに、従業員全体のOVER()を取得するには、MAX()句が必要になります。個々の行は1つの回答しか得ないため、これは正当です(サブセットではなくスーパーセットから導出されるため)。また、同じ理由で、OVER()句は、_GROUP BY_句で定義されている有効なスカラー値を参照するようになりました。 _employee_number_。


おそらくこれを簡単に言うと、aggregateOVER()節は、サブセットではなく_GROUP BY_のスーパーセットである必要があります。

必要な行を表すレベルで_GROUP BY_を使用してクエリを作成し、より高いレベルで集計する場合はOVER()句を指定します。

1
MatBailie

これはずっと前だったとしても、これはうまくいくと思います。

SELECT employee_number, Row_Number()  
   OVER (PARTITION BY course_code ORDER BY course_completion_date DESC ) as rownum
FROM employee_course_completion
WHERE course_code IN ('M910303', 'M91301R', 'M91301P')
   AND rownum = 1

日付が同じである場合に最後のIDを取得するには、主キーがIdであると仮定してこれを使用できます。

SELECT employee_number, Row_Number()  
   OVER (PARTITION BY course_code ORDER BY course_completion_date DESC, Id Desc) as rownum    FROM employee_course_completion
WHERE course_code IN ('M910303', 'M91301R', 'M91301P')
   AND rownum = 1
0
jwize