我正在尝试使用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
答案 0 :(得分: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行的CTE)。
我很惊讶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;
答案 1 :(得分: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或函数之前尝试代码 祝你好运!
修改强>
如果你想确保它总是返回奇数,即使参数ids均匀,也可以在CTE 之前的函数中添加类似的东西:
IF @oddnum%2 = 0
THEN SET @oddnum = @oddnum + 1
答案 2 :(得分: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 DEMO 强>