2017-06-15 18 views
0

distinctキーワードを使用しようとしましたが、列のグループ化を試みましたが、クエリで重複した結果が返されました。複数の結合後の重複結果

SELECT 
distinct orderformdump.itemno, 
case when PRH.ACTIVE = 1 and PRH.STARTDATE < cast(GETDATE() as DATE) and (PRH.ENDDATE IS NULL OR PRH.ENDDATE >= cast(GETDATE() as DATE)) then CAST(1 AS BIT) ELSE CAST(0 AS BIT) END as isindeal 
FROM ORDERFORMDUMP 
INNER JOIN ICITEM ON ICITEM.FMTITEMNO = orderformdump.itemno 
LEFT JOIN PRD2 on ICITEM.ITEMNO = PRD2.ITEMNO 
LEFT JOIN PRH on PRD2.CODE = PRH.CODE 
order by Itemno 

重複のいずれかに参加することにより、原因、LEFT JOIN PRD2 on ICITEM.ITEMNO = PRD2.ITEMNO、または列case when PRH.ACTIVE = 1 and PRH.STARTDATE < cast(GETDATE() as DATE) and (PRH.ENDDATE IS NULL OR PRH.ENDDATE >= cast(GETDATE() as DATE)) then CAST(1 AS BIT) ELSE CAST(0 AS BIT) END as isindealです。結合を削除してサブクエリで同じ結果を得ることはできますが、サブクエリによってクエリが非常に遅く実行されます(たとえインデックスを作成しても)。

なぜ複数の結果があり、これを解決するために何ができますか?

+0

どのようにこれを実行していますか?サブクエリではなく、テンポラリテーブルを使用してインデックスを作成する可能性はありますか? – Leonidas199x

答えて

1

はこれを試してみてください。

SELECT distinct orderformdump.itemno, isnull(tmp.isindeal, CAST(0 AS BIT)) isindeal 
FROM ORDERFORMDUMP 
INNER JOIN ICITEM ON ICITEM.FMTITEMNO = orderformdump.itemno 
outer apply 
(
select top 1 CAST(1 AS BIT) as isindeal 
from PRD2 INNER JOIN PRH on PRD2.CODE = PRH.CODE 
where ICITEM.ITEMNO = PRD2.ITEMNO and PRH.ACTIVE = 1 
and cast(GETDATE() as DATE) between PRH.STARTDATE and isnull(PRH.ENDDATE, cast(GETDATE() as DATE)) 
) tmp 
+0

OUTER APPLYでは、重複行を排除するTOP 1を使用していますが、削除された行が実際に削除する正しい行であることを確認します。私はまた、左ジョインの代わりにPRD2へのINNER JOIN PRHを使用します。クエリはPRD2から何も使用しません。最後に、BETWEENを日付に対して使用するときは注意が必要です。 > =または<=は通常、より明示的で意図を含んでおり、特に日付の値が日時になるときに意味があります。さらに、BETWEENは> =/<=のショートカットであると私は信じています。オプティマイザがそれを変更します。 – Shawn

1

はしてみてください、あなたの問題の行を見つけるには:dealCount> 1と

SELECT itemNo, count(*) as dealCount 
FROM (
    SELECT 
    distinct orderformdump.itemno, 
    case when PRH.ACTIVE = 1 and PRH.STARTDATE < cast(GETDATE() as DATE) and (PRH.ENDDATE IS NULL OR PRH.ENDDATE >= cast(GETDATE() as DATE)) then CAST(1 AS BIT) ELSE CAST(0 AS BIT) END as isindeal 
    FROM ORDERFORMDUMP 
    INNER JOIN ICITEM ON ICITEM.FMTITEMNO = orderformdump.itemno 
    LEFT JOIN PRD2 on ICITEM.ITEMNO = PRD2.ITEMNO 
    LEFT JOIN PRH on PRD2.CODE = PRH.CODE 
) t 
GROUP BY itemNO 
ORDER BY dealCount DESC 

ものはICITEM、PRD1またはPRHの複数の行を示します。次に、あなたはあなたが取り除かなければならないものを把握することができます。

参加しているテーブルの行数はいくつですか? JOINを少し変更すれば、それをより速くすることができます。 LEFT JOINとLEFT JOININGして、あなたは本当にすべてを使用していません。 PRH.ACTIVE、PRH.STARTDATE、およびPRH.ENDDATEのみを使用するため、INNER JOIN PRHをPRD2に設定し、LEFT JOININGしている結果セットをICITEMに減らすことができます。次に、私はあなたのSTARTDATEとENDDATEがDATEデータ型であり、datetimeではないことを推測しています(getDate()をDATEにキャスト)。それらがdatetimeの場合は、timeコンポーネントを考慮する必要があります。あなたのisindealのために、ビットとして1と0をキャストする必要はありません。 trueまたはfalseを表示する必要がある場合は、コードを戻してコードで処理してください。

関連する問題