0

我正在尝试使用 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 
4

3 回答 3

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;

另一种方式,如果你有一个数字表(这非常有用)。它不必包含 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

(当你使用它时,你可以创建你的函数WITH SCHEMABINDING,这有额外的好处。)

现在:

DECLARE @oddNum INT = 1;

SELECT number
  FROM dbo.Numbers
  WHERE number % 2 = 1
  AND number BETWEEN @oddNum AND 11;

所以你的功能可能是:

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

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

Gidil:                 30.31 seconds
Mahmoud:               29.11 seconds
Me (spt_values):       27.91 seconds
Me (numbers):          28.06 seconds

原因是小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;
于 2013-09-04T14:25:38.697 回答
1

尝试这样的事情:

DECLARE @oddnum INT = 1; 

WITH R_TABLE(N) 
     AS (SELECT @oddNum AS n 
         UNION ALL 
         SELECT N + 2 
         FROM   R_TABLE 
         WHERE  N < 11) 
SELECT * 
FROM   R_TABLE 

一个小建议,在将代码插入 SP 或函数之前先试用一下。
祝你好运!

编辑
如果你想确保它总是返回奇数,即使参数 id 是偶数,在 CTE 之前添加这样的东西到你的函数中:

IF @oddnum%2 = 0 

THEN SET @oddnum = @oddnum + 1 
于 2013-09-04T14:00:56.037 回答
0

这是您的解决方案,可满足您的要求:

 CREATE FUNCTION [dbo].[oddNumFunction]
 (
   @oddNum int
 )
 Returns TABLE
 AS
  RETURN
  with R_table(n)
  as 
  (
   --select @oddNum as n
   SELECT CASE WHEN @oddNum%2=0 THEN @oddNum+1 ELSE @oddNum END AS n
   union all
   select n + 2 from R_table where  n < 11 
  )
  select * from R_table 

SQLFiddle 演示

于 2013-09-04T15:14:03.113 回答