【问题标题】:dynamic sql embedded in select query嵌入在选择查询中的动态 sql
【发布时间】:2016-03-04 11:33:00
【问题描述】:

我有一张桌子Users

╔════╦═══════╦══════╗ ║身份证║姓名║数据库║ ╠════╬═══════╬══════╣ ║ 1 ║ 彼得 ║ DB1 ║ ║ 2 ║ 约翰 ║ DB16 ║ ║ 3 ║ 亚历克斯 ║ DB23 ║ ╚════╩═══════╩══════╝

而且很多数据库都有相同的结构(相同的表,相同的过程,...),所以每个数据库都有一个名为Project的表,这就是Project表的结构,

╔════╦═════════╦═════════════╗ ║ ID ║ 请求 ║ 信息 ║ ╠════╬═════════╬═════════════╣ ║ 1 ║ 126 ║ XB1 ║ ║ 2 ║ 126 ║ D6 ║ ║ 3 ║ 202 ║ BM-23 ║ ╚════╩═════════╩═════════════╝

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

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

我得到这个结果:

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

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

╔════╦═══════╦══════╦═════════════╗ ║ ID ║ 名称 ║ Db ║ NbrRequests ║ ╠════╬═══════╬══════╬═════════════╣ ║ 1 ║ 彼得 ║ DB1 ║ 2 ║ ║ 2 ║ 约翰 ║ DB16 ║ 3 ║ ║ 3 ║ 亚历克斯 ║ DB23 ║ 6 ║ ╚════╩═══════╩══════╩═════════════╝

我正在尝试使用动态 SQL,但没有成功。

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

【问题讨论】:

  • 请求表和用户表之间是否存在任何链接,而不是在特定数据库上?如果不是,每个数据库是否有多个用户,如果是,结果会是什么?
  • 请指定表关系以及您期望 nbrrequests 为 2、3、6 的方式
  • db是唯一的链接,每个用户只有一个数据库,一个数据库只属于一个用户。
  • 为什么动态 sql “不走运”?您尝试的查询是什么,遇到了什么错误?
  • @TabAlleman,运气不好,因为我找不到如何将 Users 表加入 DBxx.Project 表,我找到了解决方案,你可以看到我的答案stackoverflow.com/a/35797984/1460399

标签: sql-server tsql dynamic-sql


【解决方案1】:

您可以使用 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 表中,因为您的问题没有此类信息。

此外,为了做到这一点,您的连接用户必须对所有数据库都具有权限。

【讨论】:

  • 我觉得这个请求不是动态的,每次加用户都要改一下
  • @Hamza_L 这不是动态的。而且每次添加数据库时都必须更改它,因为这不是一项简单的任务,在查询中添加两行不会那么多。但这只是一种方法。随意选择最佳答案:)
【解决方案2】:

动态 SQL 可能非常棘手。

此示例从用户表构建选择查询。对于用户表返回的每一行,变量@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.

【讨论】:

  • 为什么会有 u.Id = p.Id ? u.Id是用户的id,p.id是项目的id
【解决方案3】:

结合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);

【讨论】:

    猜你喜欢
    • 2012-01-17
    • 2019-08-17
    • 2015-09-27
    • 2021-07-10
    • 1970-01-01
    • 2014-07-23
    • 1970-01-01
    • 1970-01-01
    • 2015-06-11
    相关资源
    最近更新 更多