SQL Server: динамические столбцы, возвращаемые из запроса
У меня довольно сложный SQL-запрос, работающий с data.stackexchange.com. Запрос можно найти по этой ссылке (и вставлен ниже).
DECLARE @Location varchar(128) = ##Location:string##
DECLARE @RepLimit int = ##RepLimit:int##
SELECT Users.DisplayName,
Users.Id,
Users.WebsiteUrl,
Users.Reputation,
(
SELECT COUNT(*)
FROM Posts
JOIN PostTags ON Posts.ParentId = PostTags.PostId
JOIN Tags ON PostTags.TagId = Tags.Id
WHERE Posts.PostTypeId = 2
AND Tags.Id = 3 -- Javascript
AND Posts.OwnerUserId = Users.Id
) AS JavascriptCount,
(
SELECT COUNT(*)
FROM Posts
JOIN PostTags ON Posts.ParentId = PostTags.PostId
JOIN Tags ON PostTags.TagId = Tags.Id
WHERE Posts.PostTypeId = 2
AND Tags.Id = 5 -- PHP
AND Posts.OwnerUserId = Users.Id
) AS PhpCount,
(
SELECT COUNT(*)
FROM Posts
JOIN PostTags ON Posts.ParentId = PostTags.PostId
JOIN Tags ON PostTags.TagId = Tags.Id
WHERE Posts.PostTypeId = 2
AND Tags.Id = 820 -- jQuery
AND Posts.OwnerUserId = Users.Id
) AS jQueryCount,
(
SELECT COUNT(*)
FROM Posts
JOIN PostTags ON Posts.ParentId = PostTags.PostId
JOIN Tags ON PostTags.TagId = Tags.Id
WHERE Posts.PostTypeId = 2
AND Tags.Id = 21 -- MySQL
AND Posts.OwnerUserId = Users.Id
) AS MySqlCount,
(
SELECT COUNT(*)
FROM Posts
JOIN PostTags ON Posts.ParentId = PostTags.PostId
JOIN Tags ON PostTags.TagId = Tags.Id
WHERE Posts.PostTypeId = 2
AND Tags.Id = 1386 -- Android
AND Posts.OwnerUserId = Users.Id
) AS AndroidCount,
(
SELECT COUNT(*)
FROM Posts
JOIN PostTags ON Posts.ParentId = PostTags.PostId
JOIN Tags ON PostTags.TagId = Tags.Id
WHERE Posts.PostTypeId = 2
AND Tags.Id IN (58338, 81106, 92809, 7003) -- IOS
AND Posts.OwnerUserId = Users.Id
) AS IosCount
FROM Users
WHERE Users.Reputation > @RepLimit
AND Users.Location = @Location
В приведенном выше запросе происходит несколько вещей:
- На data.stackexchange.com они генерируют поле формы для ввода данных, которые у меня есть
DECLARE
d вверху (в данном случае Location и RepLimit). - Теги, которые я ищу (Javascript, iOS, Android, PHP и т. Д.), Жестко закодированы, каждый из которых использует вложенный выбор, который не так эффективен, как мне кажется.
Я хочу изменить две вещи, но я не достаточно знаком с SQL Server, чтобы знать, насколько они выполнимы (а также не знаю, что именно запрашивать, чтобы найти нужные мне результаты). Два изменения:
- Я хотел бы оптимизировать запрос. Прямо сейчас я чувствую, что создание шести почти одинаковых подвыборов - не идеальный способ достижения конечного результата.
- Я хотел бы, чтобы список тегов был представлен в виде списка через запятую в новом элементе формы (будучи
DECLARE
d в верхней части, например Location и RepLimit), или в виде 5 отдельных полей формы (ограничение запроса до 5 разных тегов)
Кто-нибудь имел опыт работы с подобным запросом (или с подобной проблемой, когда фактические столбцы, возвращаемые запросом, были динамическими?). Любая помощь приветствуется.
1 ответ
Что касается вашего первого вопроса, вот способ оптимизировать запрос:
DECLARE @Location varchar(128) = ##Location:string##
DECLARE @RepLimit int = ##RepLimit:int##
SELECT Users.DisplayName,
Users.Id,
Users.WebsiteUrl,
Users.Reputation,
sum(case when Tags.Id = 3 then 1 else 0 end) as JavascriptCount,
sum(case when Tags.Id = 5 then 1 else 0 end) as PhpCount,
sum(case when Tags.Id = 820 then 1 else 0 end) as jQueryCount,
sum(case when Tags.Id = 21 then 1 else 0 end) as MySqlCount,
sum(case when Tags.Id = 1386 then 1 else 0 end) as AndroidCount,
sum(case when Tags.Id IN (58338, 81106, 92809, 7003) then 1 else 0 end) as IosCount
FROM Users
JOIN Posts ON Posts.OwnerUserId = Users.Id
JOIN PostTags ON Posts.ParentId = PostTags.PostId
JOIN Tags ON PostTags.TagId = Tags.Id
WHERE Users.Reputation > @RepLimit AND Posts.PostTypeId = 2
AND Users.Location = @Location
GROUP BY
Users.DisplayName,
Users.Id,
Users.WebsiteUrl,
Users.Reputation
Что касается вашего второго вопроса, я - как ничего не зная об этих формах стека обмена - боюсь, я не могу помочь. Но так как вы упоминаете список через запятую, вы можете использовать функцию SQL CHARINDEX() для поиска в параметре Tags.Id. Sth, как это:
case when CHARINDEX(','+convert(varchar,Tags.Id)+',',','+@List1+',') <> 0 then 1 else 0 end