これはスキーマです:
User_ID Page_ID Timestamp
1 48,51,94 7/26/2017 8:30
2 42,11,84 7/26/2017 9:40
3 4,16,24 7/26/2017 16:20
4 7,2,94 7/27/2017 8:00
1 48,22,94 7/27/2017 13:50
2 42,11 7/27/2017 14:00
3 4,24 7/27/2017 18:15
以下のコードは、ユーザーごとに実行されたページIDの集計カウントを示します(意図的に一意ではありません):
SELECT User_ID, sum(len(Page_ID) - len(replace(Page_ID, ",", "")) +1) as TotalPageCount
FROM DBTABLE
group by User_ID
出力:
User_ID TotalPageCount
1 6
2 5
3 5
4 3
ただし、(カンマ区切り)を追加しようとしていますユーザーIDごとのページIDごとのページ数の列。すなわち。ニュースレターID 1:カウント、ニュースレターID 2:カウントなどの列(基本的には辞書)。別の形式にすることもできますが、ページIDレベルで記述し、それぞれの数を指定する必要があります。
このようなもの:
User_ID PageIDCount TotalPageCount
1 48:2, 51:1, 94:2, 22:1, 6
2 42:2, 11:2, 84:1, 5
3 4:2, 16:1, 24:2, 5
4 7:1, 2:1, 94:1, 3
あなたの助けが大変ありがとう!
編集:
SeanLangeの驚くべき解決策によると、関数の使用を避けるために、定義をMyCTEから以下に変更できます。
select user_id, page_id, page_count = count(*)
FROM (
SELECT user_id, Split.a.value(".", "NVARCHAR(max)") AS page_id FROM
( SELECT user_id, CAST ("<M>" + REPLACE(page_id, ",", "</M><M>") + "</M>" AS XML) page_id
FROM #temp
) AS A
CROSS APPLY page_id.nodes ("/M") AS Split(a)
) x
group by user_id, page_id
回答:
回答№1は1うわー、これは悪夢です。最初に文字列スプリッターが必要になります。私の個人的なお気に入りはこれです。 http://www.sqlservercentral.com/articles/Tally+Table/72993/ ここには他にも多くの優れた選択肢があります。 https://sqlperformance.com/2012/07/t-sql-queries/split-strings
データから始めて、このようなことをする必要があります。
declare @Something table
(
User_ID int
, Page_ID varchar(100)
, MyDate datetime
)
insert @Something
select 1, "48,51,94", "7/26/2017 8:30" union all
select 2, "42,11,84", "7/26/2017 9:40" union all
select 3, "4,16,24", "7/26/2017 16:20" union all
select 4, "7,2,94", "7/27/2017 8:00" union all
select 1, "48,22,94", "7/27/2017 13:50" union all
select 2, "42,11", "7/27/2017 14:00" union all
select 3, "4,24", "7/27/2017 18:15"
select User_ID
, Page_ID = x.Item
, count(*)
from @Something s
cross apply dbo.DelimitedSplit8K(s.Page_ID, ",") x
group by User_ID
, x.Item
order by User_ID
, x.Item
これにより、必要なカウントのデータが取得されます。 そこから、これを希望する非正規化構造に押し戻す必要があります。 FOR XMLでこれを行うことができます。この部分を行う方法を説明した記事を次に示します。 Microsoft SQL Server 2005でgroup_concat MySQL関数をシミュレートしていますか?
----- EDIT -----
これが完全な実用的なソリューションです。 あなたは明らかにこれを整理しようと努力しています。ここではDelimitedSplit8K関数を使用しているため、ソリューションで行っているようにXMLをインライン化する必要はありませんでした。
with MyCTE as
(
select User_ID
, Page_ID = x.Item
, PageCount = count(*)
from @Something s
cross apply dbo.DelimitedSplit8K(s.Page_ID, ",") x
group by User_ID
, x.Item
)
, GroupedPageViews as
(
select c.User_ID
, sum(c.PageCount) as TotalPageCount
, PageViews = STUFF((select ", " + convert(varchar(4), c2.Page_ID) + ":" + convert(varchar(4), c2.PageCount)
from MyCTE c2
where c.User_ID = c2.User_ID
order by c2.Page_ID
for xml path("")), 1, 1, "")
from MyCTE c
group by c.User_ID
)
select gpv.User_ID
, gpv.PageViews
, gpv.TotalPageCount
from GroupedPageViews gpv
join MyCTE c on c.User_ID = gpv.User_ID
group by gpv.PageViews
, gpv.User_ID
, gpv.TotalPageCount
order by gpv.User_ID
これにより、このようなデータが返されます。
User_ID PageViews TotalPageCount
1 22:1, 48:2, 51:1, 94:2 6
2 11:2, 42:2, 84:1 5
3 16:1, 24:2, 4:2 5
4 2:1, 7:1, 94:1 3
回答№2の場合は0
どうぞ
SELECT DISTINCT User_Id
, (
SELECT CAST(t.Value AS VARCHAR) + ":" + CAST(COUNT(t.value) AS VARCHAR) + ", "
FROM TBL_46160346_DBTABLE ii
CROSS APPLY (
SELECT *
FROM fn_ParseText2Table(Page_ID, ",")
) t
WHERE pp.User_Id = ii.User_Id
GROUP BY User_Id
, VALUE
ORDER BY User_Id
FOR XML PATH("")
) PageIDCount
, (
SELECT COUNT(*)
FROM TBL_46160346_DBTABLE ii
CROSS APPLY (
SELECT *
FROM fn_ParseText2Table(Page_ID, ",")
) t
WHERE pp.User_Id = ii.User_Id
GROUP BY User_Id
) TotalPageCount
FROM TBL_46160346_DBTABLE pp
fn_ParseText2Table関数
ALTER FUNCTION [dbo].[fn_ParseText2Table] (
@p_SourceText VARCHAR(8000), @p_Delimeter VARCHAR(10) = "," --default comma
)
RETURNS @retTable TABLE (Value BIGINT)
AS
BEGIN
DECLARE @w_Continue INT, @w_StartPos INT, @w_Length INT, @w_Delimeter_pos INT, @w_tmp_txt VARCHAR(48), @w_Delimeter_Len TINYINT
IF LEN(@p_SourceText) = 0
BEGIN
SET @w_Continue = 0 -- force early exit
END
ELSE
BEGIN
-- parse the original @p_SourceText array into a temp table
SET @w_Continue = 1
SET @w_StartPos = 1
SET @p_SourceText = RTRIM(LTRIM(@p_SourceText))
SET @w_Length = DATALENGTH(RTRIM(LTRIM(@p_SourceText)))
SET @w_Delimeter_Len = LEN(@p_Delimeter)
END
WHILE @w_Continue = 1
BEGIN
SET @w_Delimeter_pos = CHARINDEX(@p_Delimeter, SUBSTRING(@p_SourceText, @w_StartPos, @w_Length - @w_StartPos + @w_Delimeter_Len))
IF @w_Delimeter_pos > 0 -- delimeter(s) found, get the value
BEGIN
SET @w_tmp_txt = LTRIM(RTRIM(SUBSTRING(@p_SourceText, @w_StartPos, @w_Delimeter_pos - 1)))
SET @w_StartPos = @w_Delimeter_pos + @w_StartPos + @w_Delimeter_Len - 1
END
ELSE -- No more delimeters, get last value
BEGIN
SET @w_tmp_txt = LTRIM(RTRIM(SUBSTRING(@p_SourceText, @w_StartPos, @w_Length - @w_StartPos + @w_Delimeter_Len)))
SELECT @w_Continue = 0
END
INSERT INTO @retTable
VALUES (@w_tmp_txt)
END
RETURN
END