SQL Server:从查询返回的动态列

时间:2013-12-20 19:27:37

标签: sql-server tsql query-optimization dataexplorer

我有一个针对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

在上面的查询中,发生了一些事情:

  1. 在data.stackexchange.com上,他们为我生成一个表单字段,输入我在顶部有DECLARE d的数据(在本例中为Location和RepLimit)。
  2. 我正在搜索的标签(Javascript,iOS,Android,PHP等)是硬编码的,每个都使用一个子选择,这不像我想象的那样高效。
  3. 我想改变两件事,但我对SQL Server不够熟悉,不知道它们是否可行(并且也不知道究竟要查询什么以找到我需要的结果)。这两个变化是:

    1. 我想优化查询。现在,我觉得制作六个几乎相同的子选择并不是实现最终结果的理想方式。
    2. 我想将标记列表提供为新表单元素中的逗号分隔列表(顶部为DECLARE d,如Location和RepLimit),或者作为5个单独的表单字段(将查询限制为最多5个不同的标签)
    3. 有没有人有类似查询的经验(或类似问题,查询返回的实际列是动态的?)。任何帮助表示赞赏。

1 个答案:

答案 0 :(得分: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。是这样的:

case when CHARINDEX(','+convert(varchar,Tags.Id)+',',','+@List1+',') <> 0 then 1 else 0 end