2016-05-03 6 views
2

私はエージェントのパフォーマンスメトリックを提供するためにコールセンターのデータに取り組んでいます。テーブルの1つは、以下の方法でエージェントステータスを取得します。この表SQL Serverで旋回するピボット

UserID | StartTime   | EndTime    | StatusKey | StateDuration | 
amjackson | 2016-04-25 12:12:14 | 2016-04-25 12:12:19 | followup |    5 | 
amjackson | 2016-04-25 12:12:19 | 2016-04-25 12:13:23 | Break  |   64 | 
amjackson | 2016-04-25 12:13:23 | 2016-04-25 12:13:42 | available |   19 | 
amjackson | 2016-04-25 12:13:42 | 2016-04-25 12:19:42 | Break  |   360 | 
amjackson | 2016-04-25 12:19:42 | 2016-04-25 12:21:55 | available |   133 | 

すべてのstatuskeyの合計秒で終日エージェントのステータスをキャプチャする私の要件はBREAK1とBREAK2としてstatuskeyに基づいてデータをピボットすることですが、休憩用の2つのcolumsをしたい

UserID | Date  | Followup | Break1 | Available | Break2 | 
amjackson | 2016-04-25 | 5  | 64 | 152  | 360 | 

ホープ・Iわかりました。 すべての入力は非常に役に立ちます。

ありがとうございました。

+0

あなたが所望の出力の例を追加することはできますか?私はあなたに何を求めているのか分かりません – m4tt1mus

答えて

0

CTEまたは派生テーブルを使用して、「Break1」または「Break2」(CASE文付き)を選択し、そこからSELECTを選択します。

0

これは多くの解釈が可能です。私はこれを読んで、あなたがBreak以外の各StatusKeyとそれぞれのブレークを合計したいと思っています。価値があるものについては、あなたのStatusKeyを別のテーブルに正規化することをお勧めしますが、それはたぶん別の日のトピックです。

ここで最初に挑戦するのは、他の人が実際にあなたの問題に容易に対応できるようにデータを投稿する必要があるということです。ここでは、サンプルデータを投稿するためのより良い方法の例を示します。

if OBJECT_ID('tempdb..#something') is not null 
    drop table #something 

create table #something 
(
    UserID varchar(10) 
    , StartTime datetime 
    , EndTime datetime 
    , StatusKey varchar(10) 
    , StateDuration int 
) 

insert #something 
select 'amjackson', '2016-04-25 12:12:14', '2016-04-25 12:12:19', 'followup', '5' union all 
select 'amjackson', '2016-04-25 12:12:19', '2016-04-25 12:13:23', 'Break', '64' union all 
select 'amjackson', '2016-04-25 12:13:23', '2016-04-25 12:13:42', 'available', '19' union all 
select 'amjackson', '2016-04-25 12:13:42', '2016-04-25 12:19:42', 'Break', '360' union all 
select 'amjackson', '2016-04-25 12:19:42', '2016-04-25 12:21:55', 'available', '133'; 

援助を受ける可能性が指数関数的に上昇するのを手助けするのは、誰かにとって非常に簡単です。

これは、この問題を解決する方法の1つです。これはもちろん、実際のデータと実際の要件について多くの仮定をしています。ここでのテクニックはクロス集計と呼ばれ、時には条件付き集計とも呼ばれます。 PIVOTを使用することもできます。私は文法が私にはあまり鈍く、少し速くなることが証明されているので、クロスタブを好む。これはおそらくあなたが述べた望ましい出力を返す少し単純化することができます。

with GroupedValues as 
(
    select UserID 
     , convert(date, StartTime) as Date 
     , StatusKey 
     , StateDuration 
     , StartTime 
    from #something 
    where StatusKey = 'Break' 

    union all 

    select UserID 
     , convert(date, max(StartTime)) as Date 
     , StatusKey 
     , SUM(StateDuration) as TotalDuration 
     , Min(StartTime) 
    from #something 
    where StatusKey <> 'Break' 
    group by UserID 
     , StatusKey 
) 
, SortedValues as 
(
    select * 
     , ROW_NUMBER() over(order by StartTime) as RowNum 
    from GroupedValues 
) 

select UserID 
    , Date 
    , Max(case when RowNum = 1 then StateDuration end) as Followup 
    , Max(case when RowNum = 2 then StateDuration end) as Break1 
    , Max(case when RowNum = 3 then StateDuration end) as Available 
    , Max(case when RowNum = 4 then StateDuration end) as Break2 
from SortedValues 
group by UserID 
    , Date 
0

私は同意します。そのデータを正規化する必要があります。とにかく、ピボットを使用したソリューションがあります。それらの区切りがどの行にあるのかわからないので、最初に非区切り行を区切り、それらのStatusKey値にIDを追加します。 グループ化が機能するためには、値を日付としてキャストする必要もあります。 ここでは、各ステータスキーのStateDuration値を追加して、それらをピボットします。 まず、テーブル変数@callcに値を入れます。

DECLARE @callc TABLE(UserID nvarchar(100), StartTime datetime, EndTime datetime 
     , StatusKey nvarchar(100), StateDuration int); 
INSERT INTO @callc(UserID, StartTime, EndTime, StatusKey, StateDuration) 
    VALUES('amjackson', '2016-04-25 12:12:14', '2016-04-25 12:12:19', 'followup', 5) 
    , ('amjackson', '2016-04-25 12:12:19', '2016-04-25 12:13:23', 'Break', 64) 
    , ('amjackson', '2016-04-25 12:13:23', '2016-04-25 12:13:42', 'available', 19) 
    , ('amjackson', '2016-04-25 12:13:42', '2016-04-25 12:19:42', 'Break', 360) 
    , ('amjackson', '2016-04-25 12:19:42', '2016-04-25 12:21:55', 'available', 133); 

SELECT UserID 
     , StartTime AS [date] 
     , [followup] 
     , [Break1] 
     , [available] 
     , [Break2] 
FROM ( SELECT c.UserID 
        , CAST(c.StartTime AS date) AS [StartTime] 
        , c.StatusKey 
        , c.StateDuration 
      FROM @callc c 
      WHERE c.StatusKey != 'Break' 
      UNION ALL 
      SELECT b.UserID 
        , CAST(b.StartTime AS date) AS [StartTime] 
        , b.StatusKey + CAST(ROW_NUMBER() OVER(ORDER BY b.StartTime ASC) AS char(2)) 
        , b.StateDuration 
      FROM @callc b 
      WHERE b.StatusKey = 'Break' 
     ) t 
PIVOT(SUM(StateDuration) FOR StatusKey IN([followup], [Break1], [available], [Break2])) p; 
+0

あなたのソリューションをありがとう、私は変数の代わりに私のテーブルを使用してみましたが、私にエラーを投げてみました "Arithameticオーバーフローエラーがデータ型varcharに式を変換する" –

0

および動的SQLと解決策:

DECLARE @query AS nvarchar(4000), 
     @columns AS nvarchar(4000) 

CREATE TABLE #temp (
    UserID nvarchar(50), 
    StartTime datetime, 
    EndTime datetime, 
    StatusKey nvarchar(50), 
    StateDuration int 
) 
INSERT INTO #temp VALUES 
('amjackson', '2016-04-25 12:12:14', '2016-04-25 12:12:19', 'followup', 5), 
('amjackson', '2016-04-25 12:12:19', '2016-04-25 12:13:23', 'Break', 64), 
('amjackson', '2016-04-25 12:13:23', '2016-04-25 12:13:42', 'available', 19), 
('amjackson', '2016-04-25 12:13:42', '2016-04-25 12:19:42', 'Break', 360), 
('amjackson', '2016-04-25 12:19:42', '2016-04-25 12:21:55', 'available', 133) 


SELECT @columns = STUFF((
SELECT ',' + QUOTENAME(StatusKey + CAST(DENSE_RANK() OVER (PARTITION BY UserID,StatusKey ORDER BY StartTime) as nvarchar(10))) 
FROM #temp 
ORDER BY StartTime ASC 
FOR XML PATH ('') 
),1,1,'') 

SELECT @query = 
'SELECT * 
FROM (
    SELECT UserID, 
      CAST(StartTime as DATE) as [Date], 
      StatusKey + CAST(DENSE_RANK() OVER (PARTITION BY UserID,StatusKey ORDER BY StartTime) as nvarchar(10)) AS StatusKey, 
      StateDuration 
    FROM #temp 
    ) as p 
PIVOT 
(
SUM(StateDuration) FOR StatusKey IN ('+[email protected]+') 
) as pvt' 

EXEC(@query) 

DROP TABLE #temp 

出力:私はそこにコメントを投稿するには評判を持っていないので、私はちょうど別のものをやる

UserID Date  followup1 Break1  available1 Break2  available2 
--------- ---------- ----------- ----------- ----------- ----------- ----------- 
amjackson 2016-04-25 5   64   19   360   133 

(1 row(s) affected) 
0

役職。あなたが得ているエラーは、そのテーブルに100以上のブレーク行があるためです。ここでは修正されたバージョンがあります。これは正しい結果をもたらすはずですが、古いものは複数のUserIDを扱うことができませんでした。 ;-)

DECLARE @callc TABLE(UserID nvarchar(100), StartTime datetime, EndTime datetime 
     , StatusKey nvarchar(100), StateDuration int); 
INSERT INTO @callc(UserID, StartTime, EndTime, StatusKey, StateDuration) 
    VALUES('amjackson', '2016-04-25 12:12:14', '2016-04-25 12:12:19', 'followup', 5) 
    , ('amjackson', '2016-04-25 12:12:19', '2016-04-25 12:13:23', 'Break', 64) 
    , ('amjackson', '2016-04-25 12:13:23', '2016-04-25 12:13:42', 'available', 19) 
    , ('amjackson', '2016-04-25 12:13:42', '2016-04-25 12:19:42', 'Break', 360) 
    , ('amjackson', '2016-04-25 12:19:42', '2016-04-25 12:21:55', 'available', 133); 

SELECT UserID 
     , StartTime AS [date] 
     , ISNULL([followup], 0) AS [followup] 
     , ISNULL([Break1], 0) AS [Break1] 
     , ISNULL([available], 0) AS [available] 
     , ISNULL([Break2], 0) AS [Break2] 
FROM ( SELECT c.UserId 
       , CAST(c.StartTime AS date) AS [StartTime] 
       , c.StatusKey 
       , c.StateDuration 
      FROM @callc c 
      WHERE c.StatusKey != 'Break' 
      UNION ALL 
      SELECT b.UserId 
       , CAST(b.startTime AS date) 
       , b.StatusKey + CAST(ROW_NUMBER() OVER(PARTITION BY UserID ORDER BY b.StartTime ASC) AS nvarchar(50)) 
       , b.StateDuration 
      FROM @callc b 
      WHERE b.StatusKey = 'Break' 
     ) t 
PIVOT(SUM(StateDuration) FOR StatusKey IN([followup], [Break1], [available], [Break2]))p; 
0

ここでは、PIVOTを使用しないで別の方法を示します。これはまた、2つ以上のブレーク、または同じ問題の同じStatusKeyを持つ他の複数の行を簡単に収容することができます。 CTEはシンプルで、StatusKeysを追加/変更すると変更する必要はありません。 SELECTを変更して別の結果が得られます。 (うまくいけば、私の例はこれを示しています。)

人口統計データコードの以前のポスターに感謝します。

-- POPULATE TEST DATA --------------------------------------------------------- 
DECLARE @callc TABLE(UserID nvarchar(100), StartTime datetime, EndTime datetime 
     , StatusKey nvarchar(100), StateDuration int); 

INSERT INTO @callc(UserID, StartTime, EndTime, StatusKey, StateDuration) 
    VALUES('amjackson', '2016-04-25 12:12:14', '2016-04-25 12:12:19', 'followup', 5) 
    , ('amjackson', '2016-04-25 12:12:19', '2016-04-25 12:13:23', 'Break', 64) 
    , ('amjackson', '2016-04-25 12:13:23', '2016-04-25 12:13:42', 'available', 19) 
    , ('amjackson', '2016-04-25 12:13:42', '2016-04-25 12:19:42', 'Break', 360) 
    , ('amjackson', '2016-04-25 12:19:42', '2016-04-25 12:21:55', 'available', 133) 
    , ('amjackson', '2016-04-25 12:22:55', '2016-04-25 12:27:55', 'Break', 300) 


;WITH CTE AS 
(
    SELECT C.UserID AS [UserID],  
      C.StateDuration AS [StateDuration],       
      CAST (C.StartTime AS DATE) AS [Date],    
      (CONCAT(C.StatusKey, CAST(ROW_NUMBER() OVER(PARTITION BY C.UserID, C.StatusKey ORDER BY C.StartTime) AS varchar(1)))) AS [StatusKey] 
    FROM @callc AS C 
) 
SELECT CTE.UserID AS [UserID], 
     CTE.Date, 
     SUM(CASE WHEN CTE.StatusKey Like 'Followup%' THEN CTE.StateDuration ELSE 0 END)      
      AS 'Followup', 
     SUM(CASE WHEN CTE.StatusKey = 'Break1' THEN CTE.StateDuration ELSE 0 END) 
      AS 'Break1', 
     SUM(CASE WHEN CTE.StatusKey LIKE 'Available%' THEN CTE.StateDuration ELSE 0 END) 
      AS 'Available', 
     SUM(CASE WHEN CTE.StatusKey = 'Break2' THEN CTE.StateDuration ELSE 0 END)  
      AS 'Break2', 

     -- Extra statuses you could easliy use 
     SUM(CASE WHEN CTE.StatusKey = 'Available2' THEN CTE.StateDuration ELSE 0 END) 
      AS 'Available2', 
     SUM(CASE WHEN CTE.StatusKey = 'Break3' THEN CTE.StateDuration ELSE 0 END)  
      AS 'Break3',    
     SUM(CASE WHEN CTE.StatusKey LIKE 'Break%' THEN CTE.StateDuration ELSE 0 END)   
      AS 'Total Breaks'     
FROM CTE 
GROUP BY 
     CTE.UserID, 
     CTE.Date; 

結果:

UserID | Date  | Followup | Break1 | Available | Break2 | Available2 | Break3 | Total Breaks 
amjackson | 2016-04-25 |  5 |  64 |  152 | 360 |  133 | 300 |   724 
関連する問題