0

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 
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 に答える
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 に答える