SQL Server:从查询返回的动态列
Posted
技术标签:
【中文标题】SQL Server:从查询返回的动态列【英文标题】:SQL Server: Dynamic columns returned from query 【发布时间】:2014-01-09 17:32:54 【问题描述】:我对 data.stackexchange.com 运行了一个相当复杂的 SQL 查询。该查询可以在this link 找到(并粘贴在下面)。
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
至于你的第二个问题——我对那些 stackexchange 表格一无所知——恐怕我无能为力。但是由于您提到了逗号分隔的列表,您可以利用 SQL 的 CHARINDEX() 函数来查找参数中的 Tags.Id。像这样的:
case when CHARINDEX(','+convert(varchar,Tags.Id)+',',','+@List1+',') <> 0 then 1 else 0 end
【讨论】:
在 StackExchange 上,当您使用DECLARE
语句时才生成表单,并且当您运行查询时,会将表单值插入到变量中进行查询。 StackExchange 只运行 SQL Server。
那么CHARINDEX
应该是一个明智的解决方案(尽管这忽略了建立在 Tags.Id 上的索引 - 因此效率大大降低)。您可能应该坚持“将查询限制为最多 5 个不同的标签”。以上是关于SQL Server:从查询返回的动态列的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server:从链接到另一个表的 ID 列动态创建列