为什么SQL Server会跳过IF语句?

时间:2018-01-05 21:42:05

标签: sql sql-server

尝试运行以下查询:

IF LEFT(CAST(SERVERPROPERTY('ProductVersion') as varchar),2) LIKE '1[2-9]'
SELECT
    @@servername AS [Server]
    , d.name AS [Database]
    , CONVERT(char(10), d.create_date, 121) AS [Created]
    , sp.name AS [Owner]
    , d.recovery_model_desc AS [Recovery]
    , CASE d.state_desc                 WHEN 'OFFLINE' THEN '***OFFLINE***' ELSE d.state_desc END AS [Status]
    , d.user_access_desc AS [Access]
    , CASE d.is_read_only               WHEN 0 THEN 'READ_WRITE' WHEN 1 THEN 'READ_ONLY' END AS Updateability
    , CASE d.is_fulltext_enabled        WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [FullText]
    , CASE d.is_auto_create_stats_on    WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [CreateStats]
    , CASE d.is_auto_update_stats_on    WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [UpdateStats]
    , CASE d.page_verify_option
        WHEN 0 THEN '***NONE***'
        WHEN 1 THEN '***TORN PAGE DETECTION***' -- outdated in 2005+. Change to checksum.
        ELSE d.page_verify_option_desc
    END AS [Page Verify]
    , d.compatibility_level AS [Level]
    , d.target_recovery_time_in_seconds as ckp_s
    , d.log_reuse_wait_desc AS [Log Wait]
    , d.collation_name AS [Collation]
    , CASE d.is_read_committed_snapshot_on  WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [RCS]
    , CASE d.snapshot_isolation_state   WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [SI]
    , CASE d.is_query_store_on WHEN 0 THEN 'NO' WHEN 1 THEN 'YES' END AS QS
    , CASE d.is_auto_close_on           WHEN 0 THEN '' WHEN 1 THEN '***YES***' /*always disable auto close*/ END AS [AutoClose]
    , CASE d.is_auto_shrink_on          WHEN 0 THEN '' WHEN 1 THEN '***YES***' /*always disable auto shrink*/ END AS [AutoShrink]
    , d.delayed_durability_desc as [Durability]
FROM sys.databases AS d
LEFT JOIN sys.server_principals AS sp /*get database owner name */ ON sp.sid = d.owner_sid
WHERE d.database_id > 4 -- exclude system DBs
ORDER BY d.name; 
ELSE
SELECT
    @@servername AS [Server]    
    , d.name AS [Database]
    , CONVERT(char(10), d.create_date, 121) AS [Created]
    , sp.name AS [Owner]
    , d.recovery_model_desc AS [Recovery]
    , CASE d.state_desc                 WHEN 'OFFLINE' THEN '***OFFLINE***' ELSE d.state_desc END AS [Status]
    , d.user_access_desc AS [Access]
    , CASE d.is_read_only               WHEN 0 THEN 'READ_WRITE' WHEN 1 THEN 'READ_ONLY' END AS Updateability
    , CASE d.is_fulltext_enabled        WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [FullText]
    , CASE d.is_auto_create_stats_on    WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [CreateStats]
    , CASE d.is_auto_update_stats_on    WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [UpdateStats]
    , CASE d.page_verify_option
        WHEN 0 THEN '***NONE***'
        WHEN 1 THEN '***TORN PAGE DETECTION***' -- outdated in 2005+. Change to checksum.
        ELSE d.page_verify_option_desc
    END AS [Page Verify]
    , d.compatibility_level AS [Level]
    , 'N/A' AS ckp_s
    , d.log_reuse_wait_desc AS [Log Wait]
    , d.collation_name AS [Collation]
    , CASE d.is_read_committed_snapshot_on  WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [RCS]
    , CASE d.snapshot_isolation_state   WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [SI]
    , 'N/A' AS QS
    , CASE d.is_auto_close_on           WHEN 0 THEN '' WHEN 1 THEN '***YES***' /*always disable auto close*/ END AS [AutoClose]
    , CASE d.is_auto_shrink_on          WHEN 0 THEN '' WHEN 1 THEN '***YES***' /*always disable auto shrink*/ END AS [AutoShrink]
    , 'N/A' AS [Durability]
FROM sys.databases AS d
LEFT JOIN sys.server_principals AS sp /*get database owner name */ ON sp.sid = d.owner_sid
WHERE d.database_id > 4 -- exclude system DBs
ORDER BY d.name;

问题出在SQL Server 2005/2008/2012上。列target_recovery_time_in_seconds, is_query_store_on, and delayed_durability_desc不存在于sys.databases表中。

顶部的IF语句查找它的SQL Server版本。如果是2014年以上,请使用这3列运行查询。如果没有,请运行没有这3列的查询。我在其他查询中使用了这个逻辑并且它可以工作,但在这种情况下却没有。我收到以下错误:

  

Msg 207,Level 16,State 1,Line 20
  列名称无效' target_recovery_time_in_seconds'。

     

Msg 207,Level 16,State 1,Line 25
  列名称无效' is_query_store_on'。

     

Msg 207,Level 16,State 1,Line 25
  列名称无效' is_query_store_on'。

     

Msg 207,Level 16,State 1,Line 28
  列名称无效' delayed_durability_desc' .`

我的问题是为什么SQL Server没有读取IF语句?如果是这样,它将跳过3列的查询并运行没有它的那个。

2 个答案:

答案 0 :(得分:2)

执行SQL查询时,首先评估整个事物。因此,当您在SQL2012或更早版本上运行它时,这些字段不存在,因此您的查询无效,因为这些字段不存在,即使该部分不会被执行。

你可以尝试使用一些动态的sql来解决这个问题 - 将整个命令构建成一个包含你需要的各种元素的字符串,并使用sp_executesql

执行它

例如:

 declare @sql nvarchar(4000)

 select @sql = 'SELECT @@servername AS [Server], d.name AS [Database] '
 -- some fields omitted here for brevity

 IF LEFT(CAST(SERVERPROPERTY('ProductVersion') as varchar),2) LIKE '1[2-9]'
 begin
     select @sql = @sql + ', CASE d.is_query_store_on WHEN 0 THEN ''NO'' WHEN 1 THEN ''YES'' END AS QS '
 end
 else
 begin
    select @sql = @sql + ', ''N/A'' as QS '
 end 
 select @sql = @sql + ' FROM sys.databases AS d LEFT JOIN sys.server_principals AS sp /*get database owner name */ ON sp.sid = d.owner_sid WHERE d.database_id > 4 -- exclude system DBs ORDER BY d.name; '

 exec sp_executesql @sql

答案 1 :(得分:2)

SQL Server将尝试编译批处理中的所有语句(除非它们引用不存在的整个对象 - 编译将被延迟。引用现有对象的缺失列不会导致延迟编译。)。

虽然只有一个查询可以在您定位的所有版本中运行,但有一个trick you can use,并且避免使用动态SQL。

以下<--标记的列将从sys.databases解析(如果它们存在于此处),或者回退到dummy派生表失败的列。

WITH d
     AS (SELECT x.*
         FROM   (SELECT  'N/A', 'N/A', 'N/A')
                AS dummy (is_query_store_on, delayed_durability_desc, target_recovery_time_in_seconds)
                CROSS APPLY (SELECT d.collation_name,
                                    d.compatibility_level,
                                    d.create_date,
                                    d.database_id,
                                    delayed_durability_desc, /* <-- resolved from d or dummy */
                                    d.is_auto_close_on,
                                    d.is_auto_create_stats_on,
                                    d.is_auto_shrink_on,
                                    d.is_auto_update_stats_on,
                                    d.is_fulltext_enabled,
                                    is_query_store_on, /* <-- resolved from d or dummy */
                                    d.is_read_committed_snapshot_on,
                                    d.is_read_only,
                                    d.log_reuse_wait_desc,
                                    d.name,
                                    d.owner_sid,
                                    d.page_verify_option,
                                    d.page_verify_option_desc,
                                    d.recovery_model_desc,
                                    d.snapshot_isolation_state,
                                    d.state_desc,
                                    target_recovery_time_in_seconds, /* <-- resolved from d or dummy */
                                    d.user_access_desc
                             FROM   sys.databases AS d) AS x)
SELECT
    @@servername AS [Server]
    , d.name AS [Database]
    , CONVERT(char(10), d.create_date, 121) AS [Created]
    , sp.name AS [Owner]
    , d.recovery_model_desc AS [Recovery]
    , CASE d.state_desc                 WHEN 'OFFLINE' THEN '***OFFLINE***' ELSE d.state_desc END AS [Status]
    , d.user_access_desc AS [Access]
    , CASE d.is_read_only               WHEN 0 THEN 'READ_WRITE' WHEN 1 THEN 'READ_ONLY' END AS Updateability
    , CASE d.is_fulltext_enabled        WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [FullText]
    , CASE d.is_auto_create_stats_on    WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [CreateStats]
    , CASE d.is_auto_update_stats_on    WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [UpdateStats]
    , CASE d.page_verify_option
        WHEN 0 THEN '***NONE***'
        WHEN 1 THEN '***TORN PAGE DETECTION***' -- outdated in 2005+. Change to checksum.
        ELSE d.page_verify_option_desc
    END AS [Page Verify]
    , d.compatibility_level AS [Level]
    , d.target_recovery_time_in_seconds as ckp_s
    , d.log_reuse_wait_desc AS [Log Wait]
    , d.collation_name AS [Collation]
    , CASE d.is_read_committed_snapshot_on  WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [RCS]
    , CASE d.snapshot_isolation_state   WHEN 0 THEN '' WHEN 1 THEN 'YES' END AS [SI]
    , CASE d.is_query_store_on WHEN 'false' THEN 'NO' WHEN 'true' THEN 'YES' ELSE 'N/A' END AS QS
    , CASE d.is_auto_close_on           WHEN 0 THEN '' WHEN 1 THEN '***YES***' /*always disable auto close*/ END AS [AutoClose]
    , CASE d.is_auto_shrink_on          WHEN 0 THEN '' WHEN 1 THEN '***YES***' /*always disable auto shrink*/ END AS [AutoShrink]
    , d.delayed_durability_desc as [Durability]
FROM d
LEFT JOIN sys.server_principals AS sp /*get database owner name */ ON sp.sid = d.owner_sid
WHERE d.database_id > 4 -- exclude system DBs
ORDER BY d.name;