动态 SQL,参数化查询

Posted

技术标签:

【中文标题】动态 SQL,参数化查询【英文标题】:Dynamic SQL, parameterized Query 【发布时间】:2017-08-04 17:58:06 【问题描述】:

我编写了一个查询来提取 SQL AlwaysON 运行状况信息。剩下要做的就是在最后添加一个 where 子句来过滤 AvailabilityGroupName 和 DatabaseName。当我输入查询时它起作用:'select * from results where AvailabilityGroupName ='LAB-VIP-USADB' AND DatabaseName ='CPS''。但是,当我在开始时将查询存储在 nvarchar 变量 @sql 中并稍后执行存储在变量中的查询时,我收到错误消息“关键字'EXEC'附近的语法不正确”。我想参数化查询的原因是一个可用性组可以包含多个数据库。参数化输入将来自 PRTG,以便查询该特定数据库的可用性组。

DECLARE @sql NVARCHAR(MAX)

SET @sql='SELECT * FROM Results WHERE AvailabilityGroupName = ''LAB-VIP-USADB'' AND DatabaseName = ''CPS'''
--select @sql
;
WITH basicaginfo AS(
SELECT 
      
       ag.name AS AvailabilityGroupName,
       cs.replica_server_name AS NodeName,
       rs.role_desc,
       rs.synchronization_health_desc,
       DB_NAME(drs.database_id) AS DatabaseName
       


FROM 
       sys.availability_groups ag
                    JOIN
       sys.dm_hadr_availability_replica_cluster_states cs on ag.group_id = cs.group_id
                    JOIN
       sys.dm_hadr_availability_replica_states rs ON (ag.group_id=rs.group_id AND cs.replica_id = rs.replica_id)
                    JOIN
       sys.dm_hadr_database_replica_states drs ON (ag.group_id=drs.group_id AND cs.replica_id = drs.replica_id)
             

					),

   
       AG_Stats AS 
                    (
                    SELECT AR.replica_server_name,
                              HARS.role_desc, 
                              Db_name(DRS.database_id) [DBName], 
                              DRS.last_commit_time
                    FROM   sys.dm_hadr_database_replica_states DRS 
                    INNER JOIN sys.availability_replicas AR ON DRS.replica_id = AR.replica_id 
                    INNER JOIN sys.dm_hadr_availability_replica_states HARS ON AR.group_id = HARS.group_id 
                           AND AR.replica_id = HARS.replica_id 
                    ),
       Pri_CommitTime AS 
                    (
                    SELECT replica_server_name
                                 , DBName
                                 , last_commit_time
                    FROM   AG_Stats
                    WHERE  role_desc = 'PRIMARY'
                    ),
       Sec_CommitTime AS 
                    (
                    SELECT replica_server_name
                                 , DBName
                                 , last_commit_time
                    FROM   AG_Stats
                    WHERE  role_desc = 'SECONDARY'
                    ),
		Results AS
					(
					SELECT 
						AvailabilityGroupName, 
						DatabaseName, 
						[LAB-SCB-SQL01],
						[LAB-SCB-SQL02], 
						[LAB-LAS-SQL01], 
						[LAB-LAS-SQL02], 
						[Max_Sync_Lag_Secs]
					FROM(
							SELECT 
								bb.AvailabilityGroupName, 
								bb.DatabaseName,
								bb.NodeName,
								bb.synchronization_health_desc,
								MAX( DATEDIFF(ss,s.last_commit_time,p.last_commit_time)) OVER ( PARTITION BY NULL ) AS [Max_Sync_Lag_Secs]
   
							FROM 
								basicaginfo bb
									LEFT JOIN
								Pri_CommitTime p ON p.DBName=bb.DatabaseName 
									LEFT JOIN 
								Sec_CommitTime s ON bb.NodeName = s.replica_server_name
						) AS Data
					PIVOT(

							MAX( synchronization_health_desc ) FOR [NodeName] IN( [LAB-SCB-SQL01], [LAB-SCB-SQL02], [LAB-LAS-SQL01], [LAB-LAS-SQL02] )
						 ) AS PivotedData
					)
EXEC(@sql)

【问题讨论】:

【参考方案1】:

你不能这样做,cte 表只能被下一个 SQL 命令访问。

当您在内部执行命令 EXEC(@sql) 时,SQL 会执行多个命令。

尝试将所有代码移动到一个变量中。

DECLARE @sql NVARCHAR(MAX)

SET @sql=N'WITH basicaginfo AS(
SELECT 

       ag.name AS AvailabilityGroupName,
       cs.replica_server_name AS NodeName,
       rs.role_desc,
       rs.synchronization_health_desc,
       DB_NAME(drs.database_id) AS DatabaseName



FROM 
       sys.availability_groups ag
                    JOIN
       sys.dm_hadr_availability_replica_cluster_states cs on ag.group_id = cs.group_id
                    JOIN
       sys.dm_hadr_availability_replica_states rs ON (ag.group_id=rs.group_id AND cs.replica_id = rs.replica_id)
                    JOIN
       sys.dm_hadr_database_replica_states drs ON (ag.group_id=drs.group_id AND cs.replica_id = drs.replica_id)


                    ),


       AG_Stats AS 
                    (
                    SELECT AR.replica_server_name,
                              HARS.role_desc, 
                              Db_name(DRS.database_id) [DBName], 
                              DRS.last_commit_time
                    FROM   sys.dm_hadr_database_replica_states DRS 
                    INNER JOIN sys.availability_replicas AR ON DRS.replica_id = AR.replica_id 
                    INNER JOIN sys.dm_hadr_availability_replica_states HARS ON AR.group_id = HARS.group_id 
                           AND AR.replica_id = HARS.replica_id 
                    ),
       Pri_CommitTime AS 
                    (
                    SELECT replica_server_name
                                 , DBName
                                 , last_commit_time
                    FROM   AG_Stats
                    WHERE  role_desc = ''PRIMARY''
                    ),
       Sec_CommitTime AS 
                    (
                    SELECT replica_server_name
                                 , DBName
                                 , last_commit_time
                    FROM   AG_Stats
                    WHERE  role_desc = ''SECONDARY''
                    ),
        Results AS
                    (
                    SELECT 
                        AvailabilityGroupName, 
                        DatabaseName, 
                        [LAB-SCB-SQL01],
                        [LAB-SCB-SQL02], 
                        [LAB-LAS-SQL01], 
                        [LAB-LAS-SQL02], 
                        [Max_Sync_Lag_Secs]
                    FROM(
                            SELECT 
                                bb.AvailabilityGroupName, 
                                bb.DatabaseName,
                                bb.NodeName,
                                bb.synchronization_health_desc,
                                MAX( DATEDIFF(ss,s.last_commit_time,p.last_commit_time)) OVER ( PARTITION BY NULL ) AS [Max_Sync_Lag_Secs]

                            FROM 
                                basicaginfo bb
                                    LEFT JOIN
                                Pri_CommitTime p ON p.DBName=bb.DatabaseName 
                                    LEFT JOIN 
                                Sec_CommitTime s ON bb.NodeName = s.replica_server_name
                        ) AS Data
                    PIVOT(

                            MAX( synchronization_health_desc ) FOR [NodeName] IN( [LAB-SCB-SQL01], [LAB-SCB-SQL02], [LAB-LAS-SQL01], [LAB-LAS-SQL02] )
                         ) AS PivotedData
                    )
                    SELECT * FROM Results WHERE AvailabilityGroupName = ''LAB-VIP-USADB'' AND DatabaseName = ''CPS'''
EXEC(@sql)

我尝试在我的环境中运行此命令,但我收到以下错误,因为我没有表格。

Msg 208, Level 16, State 1, Line 1
Invalid object name 'sys.availability_groups'.

【讨论】:

以上是关于动态 SQL,参数化查询的主要内容,如果未能解决你的问题,请参考以下文章

参数化sql查询语句

Sql Server参数化查询之where in和like实现详解

Sql Server参数化查询之where in和like实现详解

Sql Server参数化查询之where in和like实现详解

转载Sql Server参数化查询之where in和like实现详解

使用dapper进行参数化查询