web-dev-qa-db-ja.com

複数の列でグループ化し、他の列を集計し、SQL Serverですべてを選択する

SQLサーバーを使用していますが、必要なクエリを作成できません。私はいくつかの列を持つテーブルを持っています、その中には

PARAMETER_NAME、GW_LOCATION_ID、Report_Result、DETECT_FLAG

クエリで返してほしい

  1. 一意のパラメーターと場所の組み合わせごとの行
  2. その一意のパラメーターと場所の組み合わせのReport_Result列の最大値
  3. 最大値に関連付けられたDETECT_FLAG値。

DETECT_FLAG以外にも返したい列がありますが、この部分がうまく機能していれば、他の列も同様に返せるはずです。

PARAMETER_NAMEおよびGW_LOCATION_IDでグループ化し、Report_Result列を集計すると、クエリは機能します(以下を参照)。ただし、DETECT_FLAG列を追加すると、「Column 'SLVs_Flagged.DETECT_FLAG' is not invalid for the select list in it is not included in it集約関数またはGROUP BY句。 "MAX(Report_Result)によって返される行のDETECT_FLAGの値が必要です。

SELECT 
PARAMETER_NAME, GW_LOCATION_ID, MAX(Report_Result)
FROM SLVs_Flagged
GROUP BY PARAMETER_NAME, GW_LOCATION_ID
ORDER BY PARAMETER_NAME, GW_LOCATION_ID;

MAX(Report_Result)に対応するDETECT_FLAG値を返すように副選択を実行しようとしましたが、WHERE条件を使用しようとすると別のエラーが発生します。このクエリの実行方法を教えてください。

以下は、テスト用のデータのサブセットです。

PARAMETER_NAME  GW_LOCATION_ID  Report_Result   DETECT_FLAG
Perchlorate CDBO-6  2.38    N
Perchlorate CDBO-6  1.45    N
Perchlorate CDV-16-02655    4   N
Perchlorate CDV-16-02655    0.537   Y
Perchlorate CDV-16-02655    4   N
Perchlorate CDV-16-02656    100 N
Perchlorate CDV-16-02656    0.394   Y
Perchlorate CDV-16-02656    4   N
Perchlorate CDV-16-02656    4   N
Perchlorate CDV-16-02657    4   N
Perchlorate CDV-16-02657    4   N
Perchlorate CDV-16-02657    4   N
Perchlorate CDV-16-02657    0.174   Y
Perchlorate CDV-16-02658    4   N
Perchlorate CDV-16-02658    4   Y
Perchlorate CDV-16-02658    0.126   Y
Perchlorate CDV-16-02658    0.0561  Y
Perchlorate CDV-16-02658    20  N
Perchlorate CDV-16-02658    4   N
Perchlorate CDV-16-02659    4   N
Nitrate as Nitrogen R-16 S4 0.003   N
Nitrate as Nitrogen R-20 S1 0.003   N
Nitrate as Nitrogen R-20 S1 0.003   N
Nitrate as Nitrogen R-20 S1 0.003   N
Nitrate as Nitrogen R-20 S2 0.003   N
Nitrate as Nitrogen R-20 S2 0.003   N
Nitrate as Nitrogen R-20 S3 0.003   N
Nitrate as Nitrogen R-20 S3 0.003   N
Nitrate as Nitrogen R-20 S3 0.003   N
Nitrate as Nitrogen R-27    0.003   N
Nitrate as Nitrogen R-31 S2 0.003   N
Nitrate as Nitrogen R-32 S3 0.003   N
Nitrate as Nitrogen R-32 S3 0.003   N
Nitrate as Nitrogen Test Well 1A    0.01    N
Nitrate as Nitrogen Test Well 1A    -0.01   N
Nitrate as Nitrogen Test Well 2 0.04    N
Nitrate as Nitrogen Test Well 2 0.01    N
Nitrate as Nitrogen Test Well 2A    0   N
Nitrate as Nitrogen Test Well 3 0.04    N
Nitrate as Nitrogen Test Well 3 0.04    N
Nitrate as Nitrogen Test Well 4 0.04    N
Nitrate as Nitrogen Test Well 4 0.04    N
Nitrate as Nitrogen Test Well 4 0.04    N
Nitrate as Nitrogen Test Well 4 0.04    N
Nitrate as Nitrogen Test Well 4 0.04    N
Nitrate as Nitrogen Test Well 4 0.04    N
Nitrate as Nitrogen Test Well 4 0.04    N
Nitrate as Nitrogen Test Well 8 0.04    N
Nitrate as Nitrogen Test Well 8 0.04    N
1
Casivio

これはgreatest-n-per-groupの問題であり、解決する方法はたくさんあります(CROSS APPLY、ウィンドウ関数、GROUP BYを使用したサブクエリなど)。ウィンドウ関数とCTEを使用する方法は次のとおりです。

WITH ct AS
  ( SELECT *,
           rn = RANK() OVER (PARTITION BY PARAMETER_NAME, GW_LOCATION_ID
                             ORDER BY Report_Result DESC)
    FROM SLVs_Flagged
  )
SELECT PARAMETER_NAME, GW_LOCATION_ID, 
       Max_Report_Result = Report_Result,
       DETECT_FLAG
       -- more columns
FROM ct
WHERE rn = 1
ORDER BY PARAMETER_NAME, GW_LOCATION_ID ;

クエリはすべての関連付けられた結果を返します(関連付けが存在する場合)。すべての(PARAMETER_NAME, GW_LOCATION_ID)の組み合わせに対して単一の結果が必要な場合は、ROW_NUMBER()の代わりにRANK()を使用し、OVER (..)句内のORDER BYを変更することで、タイを解決できます。例えば。 (NよりYDETECT_FLAGを優先してください):

           rn = ROW_NUMBER() OVER (PARTITION BY PARAMETER_NAME, GW_LOCATION_ID
                                   ORDER BY Report_Result DESC, DETECT_FLAG)
2
ypercubeᵀᴹ

次のクエリは、より直感的に理解できると思います。

create table SLVs_Flagged (PARAMETER_NAME varchar(30), GW_LOCATION_ID varchar(30), Report_Result int, DETECT_FLAG char(1) )
go
insert into dbo.SLVs_Flagged 
values ('abc', 'cor1', 128, 'N'), ('abc', 'cor1', 12, 'Y')
, ('def', 'cor1', 500, 'Y'), ('def', 'cor1', 50, 'N')
go

;with s as (
select max(Report_Result) as Report_Result, PARAMETER_NAME,  GW_LOCATION_ID
from SLVs_Flagged 
group by PARAMETER_NAME, GW_LOCATION_ID)
SELECT s.Report_Result, s.PARAMETER_NAME,  s.GW_LOCATION_ID, t.DETECT_FLAG
FROM SLVs_Flagged t
inner join s 
on t.PARAMETER_NAME = s.PARAMETER_NAME and t.GW_LOCATION_ID = s.GW_LOCATION_ID and t.Report_Result = s.Report_Result
0
jyao