2017-04-06 5 views
0

ユーザコールデータテーブルから一意のレコードを選択するためのより良い解決策を見つけるのに苦労しています。次のように 私のテーブルの構造は次のとおりです。SQL:レコードの作成日とその他の条件に基づいてレコードをフィルタする

SELECT [MarketName], 
     [WebsiteName] , 
     [ID] , 
     [UserID], 
     [CreationDate], 
     [CallDuration], 
     [FromPhone] , 
     [ToPhone], 
     [IsAnswered], 
     [Source] 
FROM [dbo].[UserCallData] 

異なると同じIDの持つこの表の複数のエントリがあります。私は[FromPhone]と[ToPhone]が過去3ヶ月以内に何度も存在するかどうかを確認したいと思いましたが、[CreationDate]に基づいてすべての列を含む最初のレコードを選択し、発生回数をTotalCallCountとしてカウントし、totalCallDuration単一のレコードとして。 [FromPhone]と[ToPhone]が複数回発生しない場合は、すべての列をそのまま選択したいと考えました。私は以下のような部分的な質問を出すことができました。しかし、これはgroup by節に含まれていないすべての列を返すわけではなく、私の全基準を満たしていません。これに関する助言は高く評価されます。

select [FromPhone], 
     MIN([CreationDate]), 
     [ToPhone], 
     marketname, 
     count(*) as TotalCallCount , 
     sum(CallDuration) as TotalCallDuration 
from [dbo].[UserCallData] 
where [CreationDate] >= DATEADD(MONTH, -3, GETDATE()) 
group by [FromPhone],[ToPhone], marketname 
having count([FromPhone]) > 1 and count([ToPhone]) >1 
+0

お客様のご要望を理解していることは明らかです。 (a)UserCallDataテーブルの "create table"スクリプト、(b)必要な場合は匿名化されたサンプルデータ、(c)サンプルデータを入力として使用する場合の期待される出力を教えてください。データには、すべてのケースをどのように処理するかを示す行が含まれている必要があります(最小限、最後の3か月以内のもの、そうでないものもあります)。 –

答えて

0

ROW_NUMBER()

;with cte as 
(
    select *, ROW_NUMBER() OVER(PARTITION BY FromPhone, ToPhone ORDER BY CreationDate) as RN 
    from UserCallData 
    where CreationDate >= DATEADD(MONTH, -3, GETDATE()) 
), 
cte_totals as 
(
    select C1.FromPhone, C1.ToPhone, COUNT(*) as TotalCallCount, SUM(CallDuration) as TotalCallDuration 
    from cte C1 
    where exists(select * from cte C2 where C1.FromPhone = C2.FromPhone and C1.ToPhone = C2.ToPhone and C2.RN > 1) 
    group by C1.FromPhone, C1.ToPhone 
) 
select C1.*, TotalCallCount, TotalCallDuration 
from cte C1 
    inner join cte_totals C2 on C1.FromPhone = C2.FromPhone and C1.ToPhone = C2.ToPhone 
where C1.RN = 1 

を使用しようと、それはいくつかのミスやmistypesを持つことができますので、私はここにクエリを書きましたが、主なアイデアは明らかであるかもしれません。

+0

私の質問にお答えいただきありがとうございます!私はあなたのソリューションを試しましたが、最初のレコードを選択し、発生回数をTotalCallCountとしてカウントし、totalCallDurationを合計することによって、これらの複数の発生を1つのレコードにグループ化する必要があります。また、上記のクエリでは、過去3か月のデータのみが返されます。 – user7617078

+0

ありがとう!これは機能しているようです。このクエリは、複数のオカレンスが見つかった場合に一意のレコードを返すようになりました。今、上記の基準に該当しない他のレコードをどのように持ち込むのですか?(複数のレコードはありません) – user7617078

+0

私は分かりません。 1つの結果で、カウントと合計を持つ一意のレコードをすべて確認したいとしますか? – ventik

0

私は質問を理解してきた完全にわからないんだけど、私は次のようにあなたが望むこと(あるいは有用な出発点となる)ことがある場合:

私たちは一緒に行を崩壊さ
SELECT 
     ucd.FromPhone, 
     min(ucd.CreationDate) as MinCreationDate, 
     ucd.ToPhone, 
     ucd.MarketName, 
     count(*) as TotalCallCount, 
     sum(ucd.CallDuration) as TotalCallDuration, 
     case 
      when min(ucd.WebsiteName) = max(ucd.WebsiteName) then min(ucd.WebsiteName) 
      else '* Various' 
     end as WebsiteName, 
     case 
      when min(ucd.ID) = max(ucd.ID) then min(ucd.ID) 
      else '* Various' 
     end as ID, 
     case 
      when min(ucd.UserID) = max(ucd.UserID) then min(ucd.UserID) 
      else '* Various' 
     end as UserID, 
     case 
      when min(ucd.IsAnswered) = max(ucd.IsAnswered) then min(ucd.IsAnswered) 
      else '* Some' 
     end as IsAnswered, 
     case 
      when min(ucd.Source) = max(ucd.Source) then min(ucd.Source) 
      else '* Various' 
     end as Source 
FROM 
    dbo.UserCallData ucd 
WHERE 
    ucd.CreationDate >= DATEADD(MONTH, -3, GETDATE()) 
GROUP BY 
    ucd.FromPhone, 
    ucd.ToPhone, 
    ucd.MarketName 

すべての行が特定の列で一致する場合(min(Field) = max(Field))、min(Field)の値を返します(これは他のすべてと同じですが、他の場合を妨げる追加の「グループ化」句を必要とする問題を回避します)。彼らがすべて同意しない場合、私は"* something"を返しました。

コードでは、すべての列がテキスト型の列であると仮定していますが、変換エラーが発生する可能性があります。また、これらのフィールドのどれもnullではないと仮定します。これらの仮定が正しくない場合は、コードを適合させることができます。あなたがそれを自分で行うことができない場合は、私に問題を知らせてください、私はできることをやってうれしく思います。

+0

あなたのコメントをventikに基づいて、where句を削除し、GROUP BYで次のように追加することができます: 'ucd.CreationDate> = DATEADD(MONTH、-3、GETDATE())のときにグループ化し、null else ucd。 IDの終わり) '。これは、IDがテーブル内の行を一意に識別していることを前提としています。それがなければ何かが必要になります。テーブルにその種のものがない場合は、 'newid()'を使うことができます。 –

関連する問題