Подсчет количества тегов в одном посте - проводник данных - PullRequest
0 голосов
/ 29 декабря 2018

Я пытаюсь написать запрос, который будет подсчитывать количество тегов в одном сообщении.Я почему-то не могу обернуть голову, разделив теги в один ряд и посчитав эти теги.

Другие публикации предлагают создать функцию для разделения тегов, но вы не можете создавать функции для обмена данными.

Вот мой запрос, который покажет мне сообщения, которые есть и в сообщениях, и в тегах.

SELECT p.Id, p.Title, p.Tags, t.TagName
FROM Posts as p 
INNER JOIN Tags as t ON p.Id = t.Id

Ответы [ 4 ]

0 голосов
/ 29 декабря 2018

Это близко к догадкам, но мой волшебный хрустальный шар (и Мартин Смит) сказал мне, что вы можете искать что-то вроде этого:

DECLARE @mokupPosts TABLE(ID INT IDENTITY, SomePost VARCHAR(250),Tags VARCHAR(250));
INSERT INTO @mokupPosts VALUES
 ('First post','<matlab><plot><ternary><ternplot>')
,('Second post','<powershell><java><python>')
,('Third post','<image><opencv><image-processing>');

- запрос будет возвращать несколько строк вPost с каждым токеном отдельно.

SELECT p.*
      ,B.token.value('text()[1]','varchar(100)') Token
FROM @mokupPosts p
CROSS APPLY(SELECT CAST('<x>' + REPLACE(REPLACE(REPLACE(REPLACE(p.Tags,'><','||'),'<',''),'>',''),'||','</x><x>') + '</x>' AS XML)) A(Casted)
CROSS APPLY A.Casted.nodes('/x') B(token);

Вы можете легко INNER JOIN сделать это в существующей таблице Tags непосредственно на токене и выполнить группировку COUNT().

Еслитеги могут включать запрещенные символы (например, &, < and > и многие другие), вы можете использовать дополнительный внутренний SELECT FOR XML PATH(''), чтобы неявно экранировать их:

SELECT p.*
      ,B.token.value('text()[1]','varchar(100)') Token
FROM @mokupPosts p
CROSS APPLY(SELECT CAST('<x>' + REPLACE((SELECT REPLACE(REPLACE(REPLACE(p.Tags,'><','||'),'<',''),'>','') AS [*] FOR XML PATH('')),'||','</x><x>') + '</x>' AS XML)) A(Casted)
CROSS APPLY A.Casted.nodes('/x') B(token);

ОБНОВЛЕНИЕ: упрощенный подход

Внимание: Теги не должны содержать символы, запрещенные в именах элементов, например &, < and > (и многие другие)!

Этот запрос вернет список пустых элементов в формате xml , просто заменив закрывающий > с />.Затем запрос будет использовать /*, чтобы выполнить итерацию всех из них и вернуть их имя с помощью local-name(.):

SELECT p.*
      ,B.token.value('local-name(.)','varchar(100)')AS Token
FROM @mokupPosts p
CROSS APPLY(SELECT CAST(REPLACE(p.Tags,'>','/>') AS XML)) A(Casted)
CROSS APPLY A.Casted.nodes('/*') B(token)

Результат будет таким же, как указано выше ...

ОБНОВЛЕНИЕ 2:Я только что попробовал это здесь

... и это работает: -)

0 голосов
/ 29 декабря 2018

Вы можете посчитать количество тегов, используя Tags столбец:

SELECT Id, Title, Tags, LEN(Tags) - LEN(REPLACE(Tags, '<','')) AS tag_number
FROM Posts as p 
WHERE Id = 2647

SEDE Demo

0 голосов
/ 29 декабря 2018

Вы можете использовать JOIN, чтобы получить это как

SELECT P.ID,
       P.Title,
       P.Tags,
       COUNT(Tags) TagsCount
FROM Posts P INNER JOIN PostTags PT
       ON P.Id = PT.PostId
WHERE P.ID = 53243136
GROUP BY P.ID,
         P.Title,
         P.Tags;

Демонстрация SEDE

ОБНОВЛЕНИЕ:

Вот и другой способ

SELECT P.ID,
       P.Title,
       P.Tags,
       COUNT(TT.Value) - 1 TagsCount
       FROM Posts P CROSS APPLY (SELECT Value FROM STRING_SPLIT(Tags, '>')) TT
WHERE P.ID = 53243136
GROUP BY P.ID,
         P.Title,
         P.Tags; 

Демонстрация SEDE

0 голосов
/ 29 декабря 2018

Вам нужно что-то вроде этого, я думаю,

SELECT p.Id, p.Title, p.Tags, count(t.TagName)
FROM Posts as p 
INNER JOIN Tags as t ON p.Id = t.Id
group by p.Id, p.Title, p.Tags
...