2009-09-16 3 views
0

現在、SQL Server 2005関数を記述しようとしています。この関数は、パラメータとして文字列を取得し、小数点の値を持つテーブルを作成します。関数は小数点に文字列を分割しますか?

問題は、パラメータに基づいて小数点タイプを定義する必要があることです。この動作していないスニペットは、アイデアを示す必要があります:

CREATE FUNCTION [dbo].[ufn_ParseDecimal] 
(
    @Sequence VARCHAR(max), 
    @Delim CHAR(1), 
    @Prec INT, 
    @Scale INT 
) 

RETURNS @DecimalList TABLE (
fValue decimal(@Prec, @Scale) 
) 

これはどのように行うことができますか?

+2

二つのリンク:http://www.sommarskog.se/arrays-in-sql-2005.htmlとHTTP ://www.sommarskog.se/dynamic_sql.html(ダイナミックSQLは@Precと@Scaleの小数点に必要です) –

答えて

1

これは、任意のテキスト文字列を解析して値...あなたは簡単にあなたが達成しようとしているものを行うには、それを使用することができますあなたのための

ALTER FUNCTION [dbo].[ParseTextString] (@S Text, @delim VarChar(5)) 
Returns @tOut Table 
    (ValNum Integer Identity Primary Key, 
    sVal VarChar(8000)) 
As 
Begin 
Declare @dLLen TinyInt  -- Length of delimiter 
Declare @sWin VarChar(8000) -- Will Contain Window into text string 
Declare @wLen Integer  -- Length of Window 
Declare @wLast TinyInt  -- Boolean to indicate processing Last Window 
Declare @wPos Integer  -- Start Position of Window within Text String 
Declare @sVal VarChar(8000) -- String Data to insert into output Table 
Declare @BtchSiz Integer  -- Maximum Size of Window 
    Set @BtchSiz = 7900  -- (Reset to smaller values to test routine) 
Declare @dPos Integer  -- Position within Window of next Delimiter 
Declare @Strt Integer  -- Start Position of each data value within Window 
-- ------------------------------------------------------------------------- 
If @delim is Null Set @delim = '|' 
If DataLength(@S) = 0 Or 
     Substring(@S, 1, @BtchSiz) = @delim Return 
-- --------------------------- 
Select @dLLen = Len(@delim), 
     @Strt = 1, @wPos = 1, 
     @sWin = Substring(@S, 1, @BtchSiz) 
Select @wLen = Len(@sWin), 
     @wLast = Case When Len(@sWin) = @BtchSiz 
      Then 0 Else 1 End, 
     @dPos = CharIndex(@delim, @sWin, @Strt) 
-- ------------------------------------ 
    While @Strt <= @wLen 
    Begin 
     If @dPos = 0 -- No More delimiters in window 
     Begin      
      If @wLast = 1 Set @dPos = @wLen + 1 
      Else 
      Begin 
       Set @wPos = @wPos + @Strt - 1 
       Set @sWin = Substring(@S, @wPos, @BtchSiz) 
       -- ---------------------------------------- 
       Select @wLen = Len(@sWin), @Strt = 1, 
        @wLast = Case When Len(@sWin) = @BtchSiz 
           Then 0 Else 1 End, 
        @dPos = CharIndex(@delim, @sWin, 1) 
       If @dPos = 0 Set @dPos = @wLen + 1 
      End 
     End 
     -- ------------------------------- 
     Set @sVal = LTrim(Substring(@sWin, @Strt, @dPos - @Strt)) 
     Insert @tOut (sVal) Values (@sVal) 
     -- ------------------------------- 
     -- Move @Strt to char after last delimiter 
     Set @Strt = @dPos + @dLLen 
     Set @dPos = CharIndex(@delim, @sWin, @Strt) 
    End 
    Return 
End 
0

CASTとDYNAMIC SQLですが、私は関数が後者すべてをうまくサポートしているとは思いません。

EXEC 'SELECT 
    CAST(''' + 
     SUBSTRING(@SEQUENCE, 1, @Prec - @Scale) + 
     @Delim + 
     SUBSTRING(@SEQUENCE, @Prec - @Scale + 1) + 
     "'' 
     AS DECIMAL(' + @Prec + ', ' + @Scale + ')' 
1

このアドホックをSQLで定義することはできません。

できることは、動的SQLを使用してグローバル・テンポラリ・テーブル(##)を作成することです。その後、それを使用することができます。

1

T-SQLでは、関数には具体的な戻り値の型が必要です。さまざまなデータ型を含むテーブルを返すことはできません。別のプロセス(VARCHARなど)によって解釈されるように基本データに変換しない限り、これは関数の目的を覆すようです。 、あなたが行に挿入することができるはず定義されたテーブルで

DECLARE @table NVARCHAR(MAX) 
SET @table = '#DecimalTable' 

DECLARE @sql NVARCHAR(MAX) 
DECLARE @params NVARCHAR(MAX) 

SET @sql = N'CREATE TABLE ' + @table 
     + '([fValue] DECIMAL (' + @Prec + ',' + @Scale + '))' 

EXEC @sql 

:あなたは何ができるか

を使用すると、テーブル定義の精度とスケールを指定できるようになります動的SQLを使用してテーブルを作成することです同様の方法でデータを変換するために、CAST演算子を使用して:SQL Serverが暗黙のうちにあなたに挿入すると、あなたのVARCHAR(MAX)式を変換しようとして間違いなく

SET @sql = N'INSERT INTO ' + @table 
     + 'VALUES (CAST(@Seq AS DECIMAL(' + @Prec + ',' @Scale + '))' 

SET @params = N'@Seq VARCHAR(MAX)' 

EXEC sp_executesql @sql, @params, @Sequence 

、あなたも、CAST操作を必要としないかもしれませんDECIMAL列。

いずれにしても、それほど大したことではありません。動的SQLを使用する前に、問題を解決する可能性と、それがもたらすすべての頭痛を調べることをお勧めします。

+0

@Programming Heroは、_a関数が具体的な戻り値を持っていなければならないと言っています。関数とサンプルコードです。 –

+0

sql_variantは、複数の型の値を保持できる具体的な戻り値の型です。既知の型の値の表を返すことができないため、この問題には適していないようです。 –

0

他で述べたように、テーブル値付きユーザー定義関数には、各フィールドに固有の戻り値の型が必要です。

私が取り組む方法は、デザインを少し変更することです。関数が文字列のテーブルに[sequence]を分割します。まだ変換を行わないでください。

CREATE FUNCTION [dbo].[ufn_ParseList] (
    @Sequence VARCHAR(MAX), 
    @Delim CHAR(1) 
) 

RETURNS @List TABLE (
    id INT IDENTITY(1,1), 
    item VARCHAR(MAX) -- You may want to use something smaller than (MAX) 
) 

その後、必要な変換を適用してください。他の人が触れたように、これは動的SQLによって可能性があります。

しかし、コードの本体に動的SQLが存在することは、本当の痛みかもしれません...

1

私は5の精度に小数点以下をサポートするためにコード化されたが、必要に応じて、あなたがそれを増やすことができ、これを試してみてください。

CREATE FUNCTION [dbo].[ufn_ParseDecimal] 
(
    @Sequence VARCHAR(max), 
    @Delim CHAR(1), 
    @Prec INT, 
    @Scale INT 
) 
RETURNS sql_variant 
AS 

BEGIN 

DECLARE @L VARCHAR(max) 
DECLARE @R VARCHAR(max) 

IF CHARINDEX(@Delim,@Sequence)>0 
BEGIN 
    SET @L=LEFT(@Sequence,CHARINDEX(@Delim,@Sequence)-1) 
    SET @R=RIGHT(@Sequence,LEN(@Sequence)-CHARINDEX(@Delim,@Sequence)) 
END 
ELSE 
BEGIN 
    SET @[email protected] 
    SET @R='' 
END 

DECLARE @1_0 decimal(1,0) 
DECLARE @1_1 decimal(1,1) 

DECLARE @2_0 decimal(2,0) 
DECLARE @2_1 decimal(2,1) 
DECLARE @2_2 decimal(2,2) 

DECLARE @3_0 decimal(3,0) 
DECLARE @3_1 decimal(3,1) 
DECLARE @3_2 decimal(3,2) 
DECLARE @3_3 decimal(3,3) 

DECLARE @4_0 decimal(4,0) 
DECLARE @4_1 decimal(4,1) 
DECLARE @4_2 decimal(4,2) 
DECLARE @4_3 decimal(4,3) 
DECLARE @4_4 decimal(4,4) 

DECLARE @5_0 decimal(5,0) 
DECLARE @5_1 decimal(5,1) 
DECLARE @5_2 decimal(5,2) 
DECLARE @5_3 decimal(5,3) 
DECLARE @5_4 decimal(5,4) 
DECLARE @5_5 decimal(5,5) 

DECLARE @v sql_variant 

IF @Prec=1 
BEGIN 
    IF @Scale=0  BEGIN SET @1_0=RIGHT(@L,1)  SET @v= @1_0 END 
    ELSE IF @Scale=1 BEGIN SET @1_1='0.'+LEFT(@R,1) SET @v= @1_1 END 
END 
ELSE IF @Prec=2 
BEGIN 
    IF @Scale=0  BEGIN SET @2_0=RIGHT(@L,2)    SET @v= @2_0 END 
    ELSE IF @Scale=1 BEGIN SET @2_1=RIGHT(@L,1)+'.'+LEFT(@R,1) SET @v= @2_1 END 
    ELSE IF @Scale=2 BEGIN SET @2_2=   '0.'+LEFT(@R,2) SET @v= @2_2 END 
END 
ELSE IF @Prec=3 
BEGIN 
    IF @Scale=0  BEGIN SET @3_0=RIGHT(@L,3)    SET @v= @3_0 END 
    ELSE IF @Scale=1 BEGIN SET @3_1=RIGHT(@L,2)+'.'+LEFT(@R,1) SET @v= @3_1 END 
    ELSE IF @Scale=2 BEGIN SET @3_2=RIGHT(@L,1)+'.'+LEFT(@R,2) SET @v= @3_2 END 
    ELSE IF @Scale=3 BEGIN SET @3_3=   '0.'+LEFT(@R,3) SET @v= @3_3 END 
END 
ELSE IF @Prec=4 
BEGIN 
    IF @Scale=0  BEGIN SET @4_0=RIGHT(@L,4)    SET @v= @4_0 END 
    ELSE IF @Scale=1 BEGIN SET @4_1=RIGHT(@L,3)+'.'+LEFT(@R,1) SET @v= @4_1 END 
    ELSE IF @Scale=2 BEGIN SET @4_2=RIGHT(@L,2)+'.'+LEFT(@R,2) SET @v= @4_2 END 
    ELSE IF @Scale=3 BEGIN SET @4_3=RIGHT(@L,1)+'.'+LEFT(@R,3) SET @v= @4_3 END 
    ELSE IF @Scale=4 BEGIN SET @4_4=   '0.'+LEFT(@R,4) SET @v= @4_4 END 
END 
ELSE IF @Prec=5 
BEGIN 
    IF @Scale=0  BEGIN SET @5_0=RIGHT(@L,5)    SET @v= @5_0 END 
    ELSE IF @Scale=1 BEGIN SET @5_1=RIGHT(@L,4)+'.'+LEFT(@R,1) SET @v= @5_1 END 
    ELSE IF @Scale=2 BEGIN SET @5_2=RIGHT(@L,3)+'.'+LEFT(@R,2) SET @v= @5_2 END 
    ELSE IF @Scale=3 BEGIN SET @5_3=RIGHT(@L,2)+'.'+LEFT(@R,3) SET @v= @5_3 END 
    ELSE IF @Scale=4 BEGIN SET @5_4=RIGHT(@L,1)+'.'+LEFT(@R,4) SET @v= @5_4 END 
    ELSE IF @Scale=5 BEGIN SET @5_5=   '0.'+LEFT(@R,5) SET @v= @5_5 END 
END 

RETURN @v 

END 

このサンプルコードは、関数を使用しています。

 SELECT CONVERT(varchar(10),SQL_VARIANT_PROPERTY(dbo.ufn_ParseDecimal('123.4','.',4,1) , 'BaseType')),CONVERT(varchar(10),SQL_VARIANT_PROPERTY(dbo.ufn_ParseDecimal('123.4','.',4,1) , 'Precision')),CONVERT(varchar(10),SQL_VARIANT_PROPERTY(dbo.ufn_ParseDecimal('123.4','.',4,1) , 'Scale')) ,dbo.ufn_ParseDecimal('123.4','.',4,1) 
UNION SELECT CONVERT(varchar(10),SQL_VARIANT_PROPERTY(dbo.ufn_ParseDecimal('123.45','.',5,2), 'BaseType')),CONVERT(varchar(10),SQL_VARIANT_PROPERTY(dbo.ufn_ParseDecimal('123.45','.',5,2), 'Precision')),CONVERT(varchar(10),SQL_VARIANT_PROPERTY(dbo.ufn_ParseDecimal('123.45','.',5,2), 'Scale')) ,dbo.ufn_ParseDecimal('123.45','.',5,2) 
UNION SELECT CONVERT(varchar(10),SQL_VARIANT_PROPERTY(dbo.ufn_ParseDecimal('1.234','.',5,4) , 'BaseType')),CONVERT(varchar(10),SQL_VARIANT_PROPERTY(dbo.ufn_ParseDecimal('1.234','.',5,4) , 'Precision')),CONVERT(varchar(10),SQL_VARIANT_PROPERTY(dbo.ufn_ParseDecimal('1.234','.',5,4) , 'Scale')) ,dbo.ufn_ParseDecimal('1.234','.',5,4) 

OUTPUTサンプルコードから:

---------- ---------- ---------- --------- 
decimal 4   1   123.4 
decimal 5   2   123.45 
decimal 5   4   1.2340 

(3 row(s) affected) 
関連する問題