Това е схемата:
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
Кодът по-долу дава обобщен брой на изпълнените идентификатори на страници за всеки потребител (нееднозначен по предназначение):
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 1: брой, информационен бюлетин id 2: брой и т.н. Може да бъде различен формат, но трябва да бъде описателен на ниво идентификатор на страницата, със съответния брой.
Нещо като това:
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. Ето една статия, която обяснява как да се направи тази част от това. Симулиране на функцията group_concat MySQL в Microsoft SQL Server 2005?
-----РЕДАКТИРАНЕ-----
OK тук е пълното работно решение. Очевидно сте работили усилено, за да се опитате да разрешите това. Аз използвам функцията 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
0 за отговор № 2
Ето
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