3

顧客が 30 日間に同じアンケートに複数回回答した場合、1 回だけカウントしたいと考えています。誰かがそれを行うためのコードを教えてもらえますか?

テーブルを作成する
(
         CustID Char(10),
    SurveyId char(5),
    ResponseDate日時
)

#何かを挿入
「Cust1」、「100」、「5/6/13」をすべて選択
「Cust1」、「100」、「5/13/13」をすべて選択
'Cust2'、'100'、'4/20/13' ユニオンをすべて選択
「Cust2」、「100」、「5/22/13」を選択


#Something から個別の custid、SurveyId、Count(custid) を CountResponse として選択します
CustID、SurveyId でグループ化

上記のコードでは、Response の合計数のみが表示されます。30 日間に 1 回だけカウントするようにコーディングする方法がわかりません。

私が探している出力は次のようになります。

CustomerID SurveyId CountResponse
顧客1 100 1
顧客2 100 2

4

6 に答える 6

0

以下のコードは、出力例を生成する 1 つのアプローチです。ただし、 を追加した場合でも、すべての回答が以前の各アンケート回答から 30 日以内であるため、最初の回答のみがカウントされるためselect 'Cust1', '100', '4/20/13'、結果は になります。Cust1 100 1これは望ましい動作ですか?

SELECT     CustID, SurveyID, COUNT(*) AS CountResponse
FROM         #SurveysTaken
WHERE     (NOT EXISTS
                      (SELECT     1
                        FROM          #SurveysTaken AS PriorSurveys
                        WHERE      (CustID = #SurveysTaken.CustID)
                               AND (SurveyId = #SurveysTaken.SurveyId)
                               AND (ResponseDate >= DATEADD(d, - 30, #SurveysTaken.ResponseDate))
                               AND (ResponseDate < #SurveysTaken.ResponseDate)))
GROUP BY CustID, SurveyID

または、1 年を任意の 30 日間に分割して、新しい年ごとにリセットすることもできます。

SELECT     CustID, SurveyID, COUNT(*) AS CountResponse
FROM         (SELECT DISTINCT CustID, SurveyID, YEAR(ResponseDate) AS RepsonseYear,
                              DATEPART(DAYOFYEAR, ResponseDate) / 30 AS ThirtyDayPeriod
              FROM          #SurveysTaken) AS SurveysByPeriod
GROUP BY CustID, SurveyID

月ごとに移動することもできます。

SELECT     CustID, SurveyID, COUNT(*) AS CountResponse
FROM         (SELECT DISTINCT CustID, SurveyID, YEAR(ResponseDate) AS ResponseYear,
                              MONTH(ResponseDate) AS ResponseMonth
              FROM          #SurveysTaken) AS SurveysByMonth
GROUP BY CustID, SurveyID

任意のエポック日付から 30 日間を使用できます。(おそらく、調査が最初に作成された日付を別のクエリから取得することでしょうか?)

SELECT     CustID, SurveyID, COUNT(*) AS CountResponse
FROM         (SELECT DISTINCT CustID, SurveyID, DATEDIFF(D, '1/1/2013', ResponseDate) / 30 AS ThirtyDayPeriod
                       FROM          #SurveysTaken) AS SurveysByPeriod
GROUP BY CustID, SurveyID

任意の 30 期間の最後のバリエーションの 1 つは、顧客が問題の調査に初めて回答した時間に基づいて作成することです。

SELECT     CustID, SurveyID, COUNT(*) AS CountResponse
FROM         (SELECT DISTINCT CustID, SurveyID, DATEDIFF(DAY,
                                                  (SELECT     MIN(ResponseDate)
                                                    FROM          #SurveysTaken AS FirstSurvey
                                                    WHERE      (CustID = #SurveysTaken.CustID)
                                                           AND (SurveyId = #SurveysTaken.SurveyId)), ResponseDate) / 30 AS ThirtyDayPeriod
                       FROM          #SurveysTaken) AS SurveysByPeriod
GROUP BY CustID, SurveyID

エポック/期間のトリックで遭遇する問題が 1 つあります。これは、カウントされた調査が期間ごとに 1 回だけ発生するが、必ずしも 30 日離れているとは限らないということです。

于 2013-07-10T20:53:27.637 に答える
0

私は SQL Server の専門家ではありませんが、Oacle で「日付」から整数値を減算すると、事実上「日」が減算されるため、次のようなものが機能します。

SELECT custid, surveyid
FROM Something a
WHERE NOT EXISTS (
    SELECT 1
    FROM Something b
    WHERE a.custid = b.custid
    AND a.surveyid = b.surveyid
    AND b.responseDate between a.responseDate AND a.responseDate - 30
    );    

あなたのカウントを取得するには(あなたが何を求めているのか私が理解していれば):

-- Count of times custID returned surveyID, not counting same
-- survey within 30 day period.
SELECT custid, surveyid, count(*) countResponse
FROM Something a
WHERE NOT EXISTS (
    SELECT 1
    FROM Something b
    WHERE a.custid = b.custid
    AND a.surveyid = b.surveyid
    AND b.responseDate between a.responseDate AND a.responseDate - 30
    )
GROUP BY custid, surveyid

更新: 以下で提起されたケースごとに、これは実際にはうまくいきません。おそらく行うべきことは、テーブルを繰り返し処理し、something保持したい調査の行をテーブルに挿入してから、テーブルとresults比較して、results考慮したい過去 30 日間に受信した調査が既にあるかどうかを確認することです。Oracle PL/SQL でこのようなことを行う方法を示すことはできますが、SQL サーバーの構文はわかりません。おそらく、SQL Server を知っている他の誰かがこの戦略を盗んで答えをコード化したいと考えているかもしれません。あるいは、これで十分であるかもしれません。

于 2013-07-10T20:30:22.857 に答える
0

調査が最初に送信されてから 30 日として計算される生理期間が必要であるという理論に進むと、ここに (全体的な) 解決策があります。

declare @Something table
(
    CustID Char(10),
    SurveyId char(5),
    ResponseDate datetime
)

insert @Something
select 'Cust1', '100', '5/6/13' union all
select 'Cust1', '100', '5/13/13' union all
select 'Cust1', '100', '7/13/13' union all
select 'Cust2', '100', '4/20/13' union all
select 'Cust2', '100', '5/22/13' union all
select 'Cust2', '100', '7/20/13' union all
select 'Cust2', '100', '7/24/13' union all
select 'Cust2', '100', '9/28/13' 

--SELECT CustID,SurveyId,COUNT(*) FROM (

select a.CustID,a.SurveyId,b.ResponseStart,--CONVERT(int,a.ResponseDate-b.ResponseStart),
CASE 
    WHEN CONVERT(int,a.ResponseDate-b.ResponseStart) > 30 
    THEN ((CONVERT(int,a.ResponseDate-b.ResponseStart))-(CONVERT(int,a.ResponseDate-b.ResponseStart) % 30))/30+1
    ELSE 1
END CustomPeriod -- defines periods 30 days out from first entry of survey
from @Something a
inner join
(select CustID,SurveyId,MIN(ResponseDate) ResponseStart
from @Something
group by CustID,SurveyId) b
on a.SurveyId=b.SurveyId
and a.CustID=b.CustID
group by a.CustID,a.SurveyId,b.ResponseStart,
CASE 
    WHEN CONVERT(int,a.ResponseDate-b.ResponseStart) > 30 
    THEN ((CONVERT(int,a.ResponseDate-b.ResponseStart))-(CONVERT(int,a.ResponseDate-b.ResponseStart) % 30))/30+1
    ELSE 1
END

--) x GROUP BY CustID,SurveyId

少なくとも、CASE ステートメントを関数にして、読みやすくしたいと思うでしょう。別のテーブルで明示的なウィンドウを定義することをお勧めします。期間 1 の終わりに調査が返され、数日後の期間 2 に別の調査が返されるような状況を避けたい場合、これは実行できない場合があります。

可能であれば、入力時にこれを処理することを検討してください。たとえば、オンライン調査で顧客を特定している場合は、調査への回答を拒否します。または、誰かがこれらを郵送している場合、データ入力担当者が 30 日以内に来たら拒否するようにします。

または、「ワイルドでクレイジー」と同じ行に沿って、ビットと INSERT トリガーを追加します。その顧客のそのタイプの調査が期間内に見つからない場合にのみ、ビットをオンにします。

全体として、この問題をもう少し完全に表現すると役立つでしょう。ただし、実際のコード例には感謝しています。

于 2013-07-10T21:38:39.530 に答える
0

私をワイルドでクレイジーと呼んでいますが、私は各調査でより多くの状態を保存することでこの問題を解決します. 私がとるアプローチはbit、特定の調査をカウントする必要があるかどうかを示すタイプ列 (つまり、Countable列) を追加することです。これにより、これを関係的に解決することに固有の状態追跡の問題が解決されます。

過去 30 日間に/が 1 に設定された調査が見つからCountableない場合は、挿入時に値を 1 に設定します。それ以外の場合は 0 に設定します。CustIDSurveyIdCountable

その後、問題は自明に解決可能になります。CustID/でグループ化し、列SurveyIdの値を合計するだけです。Countable

このアプローチの 1 つの注意点は、調査を時系列で追加する必要があり、Countable値を再計算しないと削除できないことです。

于 2013-07-10T20:34:49.317 に答える