【问题标题】:Using the "With Clause" SQL Server 2008使用“With 子句”SQL Server 2008
【发布时间】:2011-01-14 21:16:33
【问题描述】:

谁能给我看一个使用 “With Clause” 的示例 SQL 服务器脚本,我可以查看它吗?

我正在尝试使用此子句遍历 200 个数据库,这些数据库包含我尝试对其运行查询的同一表。我试图避免使用游标,因为查询时间太长以及使用 while 循环。

谁能告诉我我能做什么。

谢谢。

【问题讨论】:

  • WITH 不会帮助您完成这项任务。所有数据库都在同一个实例上吗?你在它们上面运行的代码是什么?
  • Martin,是的,他们在同一个实例上。每个数据库都有相同的表。我想使用 sum 函数从表中收集所有数据,并将每个数据库的名称填充到一个临时表中,其中包含以下列:DBNAME、IMG_COUNT、DATE。表的名称是 tbldoc 或 dbo.tbldoc。每个数据库都包含此表,并且都具有我希望查询的相同列。相比使用游标或 while 循环,如何加快速度?

标签: sql-server-2008 sql-server-2008-r2


【解决方案1】:

只是一个戳,但这里有另一种写 FizzBu​​zz 的方法 :) 我认为 100 行足以显示 WITH 语句。

;WITH t100 AS (
 SELECT n=number
 FROM master..spt_values
 WHERE type='P' and number between 1 and 100
)                
 SELECT
    ISNULL(NULLIF(
    CASE WHEN n % 3 = 0 THEN 'Fizz' Else '' END +
    CASE WHEN n % 5 = 0 THEN 'Buzz' Else '' END, ''), RIGHT(n,3))
 FROM t100

但在 SQL Server 2005 及更高版本中 WITH(称为通用表表达式 http://msdn.microsoft.com/en-us/library/ms190766.aspx“CTE”)背后的真正强大之处在于递归,如下所示,表是通过每次添加到虚拟表的迭代来构建的.

;WITH t100 AS (
 SELECT n=1
 union all
 SELECT n+1
 FROM t100
 WHERE n < 100
)                
 SELECT
    ISNULL(NULLIF(
    CASE WHEN n % 3 = 0 THEN 'Fizz' Else '' END +
    CASE WHEN n % 5 = 0 THEN 'Buzz' Else '' END, ''), RIGHT(n,3))
 FROM t100

要在所有数据库中运行类似的查询,您可以使用未记录的 sp_msforeachdb。在另一个答案中已经提到过,但它是 sp_msforeachdb,而不是 sp_foreachdb。

使用它时要小心,因为有些事情不是你所期望的。考虑这个例子

exec sp_msforeachdb 'select count(*) from sys.objects'

您将得到报告的相同计数,而不是每个 DB 中的对象计数,从当前 DB 开始。 要解决这个问题,请始终首先“使用”数据库。请注意方括号以限定多词数据库名称。

exec sp_msforeachdb 'use [?]; select count(*) from sys.objects'

对于有关填充计数表的特定查询,您可以使用如下所示的内容。不确定 DATE 列,因此此计数表只有 DBNAME 和 IMG_COUNT 列,但希望对您有所帮助。

create table #tbl (dbname sysname, img_count int);

exec sp_msforeachdb '
use [?];
if object_id(''tbldoc'') is not null
insert #tbl
select ''?'', count(*) from tbldoc'

select * from #tbl

【讨论】:

  • 好的,对我来说,最好的方法似乎是使用一个 while 循环,与 while 循环相比,它的处理速度应该更快。这就是我到目前为止所拥有的
  • 这对我实现网格的分页按钮点击获取数据帮助很大。非常感谢。
【解决方案2】:

WITH子句有两种类型:

这是 SQL 形式的 FizzBu​​zz,使用 WITH 公用表表达式 (CTE)。

;WITH mil AS (
 SELECT TOP 1000000 ROW_NUMBER() OVER ( ORDER BY c.column_id ) [n]
 FROM master.sys.all_columns as c
 CROSS JOIN master.sys.all_columns as c2
)                
 SELECT CASE WHEN n  % 3 = 0 THEN
             CASE WHEN n  % 5 = 0 THEN 'FizzBuzz' ELSE 'Fizz' END
        WHEN n % 5 = 0 THEN 'Buzz'
        ELSE CAST(n AS char(6))
     END + CHAR(13)
 FROM mil

这是一个同样使用 WITH 子句的 select 语句

SELECT * FROM orders WITH (NOLOCK) where order_id = 123

【讨论】:

    【解决方案3】:

    尝试 sp_foreachdb 过程。

    【讨论】:

    • 这只是使用光标,所以在 OP 当前系统上可能不会有显着的速度性能(不是我怀疑这是可能的)
    • Martin,是的,他们在同一个实例上。每个数据库都有相同的表。我想在特定列上使用 sum 函数来收集表中的所有数据,并将每个数据库的名称填充到一个带有以下列的临时表中:DBNAME、IMG_COUNT、DATE。表的名称是 tbldoc 或 dbo.tbldoc。每个数据库都包含此表,并且都具有我希望查询的相同列。怎样做才能加快速度,而不是使用游标或 while 循环?
    • 没有循环就没有办法做到这一点。然而,大部分时间将用于单个查询而不是循环本身。您可以 (1) 尝试将其并行化。 (2) 确保所有数据库中的tbldoc 具有适合正在运行的查询的索引或 (3) 尝试引入一些预先计算。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-12
    • 2014-03-30
    • 1970-01-01
    • 2013-12-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多