Sql server 函数返回范围内的奇数

Sql server 函数返回范围内的奇数,sql-server,sql-server-2008,tsql,Sql Server,Sql Server 2008,Tsql,我正在尝试使用CTE生成脚本内联值函数 如果我输入1,表格只显示奇数,当我输入n

我正在尝试使用CTE生成脚本内联值函数 如果我输入1,表格只显示奇数,当我输入n<11时,它显示1,3,5,7,9,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 

试着这样做:

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 

试着这样做:

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 

与使用递归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;
另一种方法是,如果你有一个非常有用的数字表。它不必包含1000000行,这只是为了证明它可以。使用压缩,这需要11MB;没有,13MB

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
当您使用它时,您可以使用SCHEMABINDING创建您的函数,这有额外的好处

现在:

因此,您的功能可以是:

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
  );
性能比较,运行10000次并将输出填充到临时表中:

Gidil:                 30.31 seconds
Mahmoud:               29.11 seconds
Me (spt_values):       27.91 seconds
Me (numbers):          28.06 seconds
原因是小的spt_值表已经在内存中,我们强制数字表在内存中,需要读取的逻辑数很少!比递归CTE的计算成本更低,即使是最多只生成6行的CTE

我很惊讶马哈茂德的测试结果比吉迪尔的快,但我运行了多次,结果是一致的。你可以试着自己测试并比较它们。虽然在大多数情况下,这种性能差异是可以忽略不计的,但我不会用手去挥动这些东西,如果我找到了我所知道的最有效的方法去做某事,我宁愿使用它,即使亚军紧随其后

如果您真的希望这是一个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;

与使用递归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;
另一种方法是,如果你有一个非常有用的数字表。它不必包含1000000行,这只是为了证明它可以。使用压缩,这需要11MB;没有,13MB

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
当您使用它时,您可以使用SCHEMABINDING创建您的函数,这有额外的好处

现在:

因此,您的功能可以是:

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
  );
性能比较,运行10000次并将输出填充到临时表中:

Gidil:                 30.31 seconds
Mahmoud:               29.11 seconds
Me (spt_values):       27.91 seconds
Me (numbers):          28.06 seconds
原因是小的spt_值表已经在内存中,我们强制数字表在内存中,需要读取的逻辑数很少!比递归CTE的计算成本更低,即使是最多只生成6行的CTE

我很惊讶马哈茂德的测试结果比吉迪尔的快,但我运行了多次,结果是一致的。你可以试着自己测试并比较它们。虽然在大多数情况下,这种性能差异是可以忽略不计的,但我不会用手去挥动这些东西,如果我找到了我所知道的最有效的方法去做某事,我宁愿使用它,即使亚军紧随其后

如果您真的希望这是一个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;

这是您的解决方案,针对您的需求进行了修复:

 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 

这是您的解决方案,针对您的需求进行了修复:

 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 

n+2而不是n+1然后如果我放入@oddnum2,它将给出2,4,6…..当@oddNum%2=0时,将select@oddNum作为n替换为select CASE,然后当@oddNum%2=0时,将@oddNum+1 ELSE@oddNum END作为nn+2而不是n+1;如果我放入@oddnum2,它将给出2,4,6…..当@oddNum%2=0时,将select@oddNum作为n替换为select CASE@oddNum+1 ELSE@oddNum END作为nn@Dongmin为什么您必须使用递归CTE吗?这是学校的作业吗?否则,为什么会有人为的要求呢?来到SQL Server 2016,隐秘的CTE。。。避免与他人作伴;孤独是的,这是。因此,我想要线索:3课程材料中是否没有任何关于如何构建递归CTE的信息?讲师知道你在这里得到帮助吗?在课程材料中,它只提供了CTE的信息。我需要从网上找到线索。所以我需要信息:D@Dongmin为什么必须使用递归CTE?这是学校的作业吗?否则,为什么会有人为的要求呢?来到SQL Server 2016,隐秘的CTE。。。避免与他人作伴;孤独是的,这是。因此,我想要线索:3课程材料中是否没有任何关于如何构建递归CTE的信息?讲师知道你在这里得到帮助吗?在课程材料中,它只提供了CTE的信息。我需要从网上找到线索。所以我需要信息:D汉克斯:D帮了大忙汉克斯:D帮了大忙