次のSQLテーブルがあります。
AR_Customer_ShipTo
+--------------+------------+-------------------+------------+
| ARDivisionNo | CustomerNo | CustomerName | ShipToCode |
+--------------+------------+-------------------+------------+
| 00 | 1234567 | Test Customer | 1 |
| 00 | 1234567 | Test Customer | 2 |
| 00 | 1234567 | Test Customer | 3 |
| 00 | ARACODE | ARACODE Customer | 1 |
| 00 | ARACODE | ARACODE Customer | 2 |
| 01 | CBE1EX | Normal Customer | 1 |
| 02 | ZOCDOC | Normal Customer-2 | 1 |
+--------------+------------+-------------------+------------+
(ARDivisionNo, CustomerNo,ShipToCode)
は、このテーブルの主キーを形成します。
最初の3行が同じ顧客(テスト顧客)に属し、異なるShipToCodesがある場合:1、2、3。2番目の顧客(ARACODE顧客)も同様です。通常の顧客と通常の顧客-2のそれぞれには、単一のShipToCode
を持つ1つのレコードのみがあります。
ここで、このテーブルで結果のクエリを取得したいのですが、顧客ごとに1つのレコードしかありません。したがって、複数のレコードがある顧客の場合、ShipToCode
の値が最も高いレコードを保持したいと思います。
私はさまざまなことを試しました:
(1)テーブルにレコードが1つしかない顧客のリストを簡単に取得できます。
(2)次のクエリを使用すると、テーブルに複数のレコードがあるすべての顧客のリストを取得できます。
[クエリ-1]
SELECT ARDivisionNo, CustomerNo
FROM AR_Customer_ShipTo
GROUP BY ARDivisionNo, CustomerNo
HAVING COUNT(*) > 1;
(3)さて、上記のクエリによって返された各レコードに適切なShipToCode
を選択するために、上記のクエリによって返されたすべてのレコードを反復処理する方法がわかりません。
私が次のようなことをした場合:
[クエリ-2]
SELECT TOP 1 ARDivisionNo, CustomerNo, CustomerName, ShipToCode
FROM AR_Customer_ShipTo
WHERE ARDivisionNo = '00' and CustomerNo = '1234567'
ORDER BY ShipToCode DESC
その後、(00-1234567-Test Customer)の適切なレコードを取得できます。したがって、上記のクエリ(クエリ2)でクエリ1のすべての結果を使用できる場合、複数のレコードを持つ顧客に必要な単一のレコードを取得できます。これをポイント(1)の結果と組み合わせて、目的の最終結果を得ることができます。
繰り返しますが、これは私が従っているアプローチよりも簡単です。どうすればいいのか教えてください。
[注:SQLクエリのみを使用してこれを行う必要があります。ストアドプロシージャは使用できません。最終的に 'Scribe Insight'を使用してこの処理を実行するため、クエリの作成のみが許可されます。]
1)CTEを使用して、各顧客のARDivisionNo、CustomerNoに基づいて最大出荷コード値レコードを取得します。
WITH cte AS (
SELECT*,
row_number() OVER(PARTITION BY ARDivisionNo, CustomerNo ORDER BY ShipToCode desc) AS [rn]
FROM t
)
Select * from cte WHERE [rn] = 1
2)レコードを削除するには、選択の代わりに削除クエリを使用し、Where句をrn> 1に変更します。 Sample SQL FIDDLE
WITH cte AS (
SELECT*,
row_number() OVER(PARTITION BY ARDivisionNo, CustomerNo ORDER BY ShipToCode desc) AS [rn]
FROM t
)
Delete from cte WHERE [rn] > 1;
select * from t;
SQL Serverのバージョンを指定しませんでしたが、ROW_NUMBERはおそらくサポートされています。
select *
from
(
select ...
,row_number()
over (partition by ARDivisionNo, CustomerNo
order by ShipToCode desc) as rn
from tab
) as dt
where rn = 1
ROW_NUMBER()
はこれに最適です:
_;WITH cte AS (SELECT *,ROW_NUMBER() OVER(PARTITION BY ARDivisionNo,CustomerNo ORDER BY ShipToCode DESC) AS RN
FROM AR_Customer_ShipTo
)
SELECT *
FROM cte
WHERE RN = 1
_
DELETE
にしたい場合は、単純に次のようにできます:
_;WITH cte AS (SELECT *,ROW_NUMBER() OVER(PARTITION BY ARDivisionNo,CustomerNo ORDER BY ShipToCode DESC) AS RN
FROM AR_Customer_ShipTo
)
DELETE cte
WHERE RN > 1
_
ROW_NUMBER()
関数は、各行に番号を割り当てます。 _PARTITION BY
_はオプションですが、指定されたフィールドまたはフィールドのグループの各値の番号付けを開始するために使用されます。つまり、_PARTITION BY Some_Date
_の場合、一意の日付値ごとに番号付けは1から始まります。 _ORDER BY
_は、もちろん、カウントの進め方を定義するために使用され、ROW_NUMBER()
関数で必要です。
row_number
関数:
SELECT * FROM(
SELECT ARDivisionNo, CustomerNo, CustomerName, ShipToCode,
row_number() over(partition by CustomerNo order by ShipToCode desc) rn
FROM AR_Customer_ShipTo) t
WHERE rn = 1