动态sql嵌入在select查询中

时间:2016-03-04 11:33:01

标签: sql-server tsql dynamic-sql

我有一张表Users

╔════╦═══════╦══════╗
║ Id ║ Name  ║  Db  ║
╠════╬═══════╬══════╣
║  1 ║ Peter ║ DB1  ║
║  2 ║ John  ║ DB16 ║
║  3 ║ Alex  ║ DB23 ║
╚════╩═══════╩══════╝

和许多具有相同结构的数据库(相同的表,相同的过程......),因此每个数据库都有一个名为Project的表,这是Project表的结构,< / p>

╔════╦═════════╦═════════════╗
║ Id ║ Request ║ Information ║
╠════╬═════════╬═════════════╣
║  1 ║     126 ║ XB1         ║
║  2 ║     126 ║ D6          ║
║  3 ║     202 ║ BM-23       ║
╚════╩═════════╩═════════════╝

所以,当我查询数据库时:

SELECT count(distinct([Request])) as nbrRequests
  FROM [SRV02].[DB1].[dbo].[Project]

我得到了这个结果:

╔═════════════╗
║ NbrRequests ║
╠═════════════╣
║           2 ║
╚═════════════╝

现在,我想要的是从表Users“链接”/“加入”...结果到此查询,其中Db表中的列Users是我的数据库的名称,所以我可以得到这样的结果:

╔════╦═══════╦══════╦═════════════╗
║ Id ║ Name  ║  Db  ║ NbrRequests ║
╠════╬═══════╬══════╬═════════════╣
║  1 ║ Peter ║ DB1  ║           2 ║
║  2 ║ John  ║ DB16 ║           3 ║
║  3 ║ Alex  ║ DB23 ║           6 ║
╚════╩═══════╩══════╩═════════════╝

我正在尝试使用动态SQL,但没有运气。

NB:每个用户只有一个数据库,数据库只属于一个用户,这是一对一的关系

3 个答案:

答案 0 :(得分:3)

你可以这样做的方法是使用UNION计算每个特定的数据库表并为其提供数据库的标识,如下所示:

SELECT u.Id, u.Name, u.Db, dbCts.nbrRequests
  FROM [Users] u INNER JOIN
      (SELECT 'DB1' as db, count(distinct([Request])) as nbrRequests
         FROM [SRV02].[DB1].[dbo].[Project]
       UNION 
       SELECT 'DB16', count(distinct([Request])) as nbrRequests
         FROM [SRV02].[DB16].[dbo].[Project]
       UNION  
       SELECT 'DB23', count(distinct([Request])) as nbrRequests
         FROM [SRV02].[DB23].[dbo].[Project]
      ) dbCts ON u.Db = dbCts.db

不要忘记将服务器和架构添加到我没有的Users表中,因为您的问题没有此类信息。

此外,为了执行此操作,您的已连接用户必须拥有所有数据库的权限。

答案 1 :(得分:1)

动态SQL可能非常棘手。

此示例从users表构建select查询。对于Users表返回的每一行,变量@Query都会递增。每行返回一个查询,该查询将本地用户表连接到远程数据库中的项目表。每个查询的结果都是UNIONED

示例

-- Wil holds our dynamic query.
DECLARE @Query NVARCHAR(MAX) = '';

-- Builds our dynamic statement.
SELECT
    @Query = 
        @Query 
        + CASE WHEN LEN(@Query) > 0 THEN ' UNION ALL ' ELSE '' END
        + 'SELECT u.Id, u.Name, u.Db, COUNT(DISTINCT p.Request) AS NbrRequest '
        + 'FROM [SVR02].' + QUOTENAME(DB) + 'dbo.Project AS p INNER JOIN Users u ON u.Db= p.Db '
        + 'GROUP BY u.Id, u.Name, u.Db'
FROM
    Users
;

-- Executes the dynamic statement.
EXECUTE (@Query);

此示例使用QUOTENAME来帮助避免SQL injection attacks.

答案 2 :(得分:1)

结合这两个答案https://stackoverflow.com/a/35795690/1460399https://stackoverflow.com/a/35795189/1460399,我得到了这个解决方案:

DECLARE @Query NVARCHAR(MAX)= 'SELECT u.Id, u.Name, u.Db, dbCts.nbrRequests  FROM [Users] u INNER JOIN (';

DECLARE @QueryLength INT= LEN(@Query);

SELECT @Query = @Query
                +CASE WHEN LEN(@Query) > @QueryLength THEN ' UNION ' ELSE '' END
               +'SELECT '''+Db+''' as db, count(distinct(Request)) as nbrRequests FROM [SRV02].'+Db+'[Project]'
FROM Users;

SET @Query = @Query+') dbCts ON u.Db = dbCts.db';

EXECUTE (@Query);