用于返回范围内的奇数的函数

0 t-sql sql-server sql-server-2008

我试图用CTE制作脚本内联值函数我想要一个表只显示奇数如果我输入(1)它显示1,3,5,7,9,11因为我把n <11这个脚本显示每个数字1到11.我应该添加什么?

 CREATE FUNCTION [dbo].[oddNumFunction]
 (
 @oddNum int
 )
 Returns TABLE
 AS
 RETURN
 with R_table(n)
 as 
 (
 select @oddNum as n
 union all
 select n + 1 from R_table where  n < 11 

 )
 select * from R_table 
Run Code Online (Sandbox Code Playgroud)

Aar*_*and 5

而不是使用递归CTE,我会寻求更简单的东西:

DECLARE @oddNum INT = 1;

SELECT number
 FROM master..spt_values
 WHERE [type] = N'P' 
  AND number % 2 = 1
  AND number BETWEEN @oddNum AND 11;
Run Code Online (Sandbox Code Playgroud)

另一种方法,如果你有一个数字表(非常有用).它不必包含1,000,000行,这只是为了证明它可以.通过压缩,这需要11 MB; 没有,13 MB.

CREATE TABLE dbo.Numbers(number INT PRIMARY KEY)
 WITH (DATA_COMPRESSION = PAGE); -- recommended if your edition supports it

INSERT dbo.Numbers(number) SELECT TOP (1000000) 
  ROW_NUMBER() OVER (ORDER BY s1.[object_id]) 
  FROM sys.all_objects AS s1 
  CROSS JOIN sys.all_objects AS s2;

SELECT number FROM dbo.Numbers; -- prime it
Run Code Online (Sandbox Code Playgroud)

(当你使用它时,你可以创建你的功能WITH SCHEMABINDING,这有额外的好处.)

现在:

DECLARE @oddNum INT = 1;

SELECT number
  FROM dbo.Numbers
  WHERE number % 2 = 1
  AND number BETWEEN @oddNum AND 11;
Run Code Online (Sandbox Code Playgroud)

所以你的功能可能是:

CREATE FUNCTION [dbo].[oddNumFunction2]
(
  @oddNum INT
)
RETURNS TABLE
WITH SCHEMABINDING
AS
  RETURN
  (
    SELECT number
      FROM dbo.Numbers
      WHERE number % 2 = 1
      AND number BETWEEN @oddNum AND 11
  );
Run Code Online (Sandbox Code Playgroud)

性能比较,运行10,000次(并将输出填充到#temp表中):

Gidil:                 30.31 seconds
Mahmoud:               29.11 seconds
Me (spt_values):       27.91 seconds
Me (numbers):          28.06 seconds
Run Code Online (Sandbox Code Playgroud)

原因是小spt_values表已经在内存中(并且我们强制使用数字表),并且所需的逻辑数量较少(略微!)比递归CTE的计算成本低(即使只生成一个最多6行).

令我感到惊讶的是,Mahmoud比Gidil的出现速度更快,但我多次运行并且结果一致.感觉尝试自己测试并比较.虽然在大多数情况下这种性能差异可以忽略不计,但我并没有动摇这些东西,如果我找到了最有效的方法,我就会更好地使用它,即使亚军是紧跟其后.


如果你真的希望这是一个CTE,下面将处理0到11之间任何输入(奇数或偶数)的奇数:

DECLARE @oddnum INT = 1;

;WITH n(n) AS
( 
  SELECT @oddNum + ((@oddNum-1)%2)
  UNION ALL
  SELECT n + 2 FROM n WHERE n < 11
)
SELECT n FROM n;
Run Code Online (Sandbox Code Playgroud)