1

渡された文字列値のリストの中で最大のものを見つける関数が必要でした。

SQLサーバーからSelectgreatest('Abcd'、'Efgh'、'Zxy'、'EAD')として呼び出したい。Zxyを返すはずです。パラメータの数は可変です。ちなみに、これはoracleGREATEST関数と非常によく似ています。そこで、非常に単純なCLR関数(Vs2008)を作成し、それをデプロイしようとしました。下記参照

public partial class UserDefinedFunctions
{
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString Greatest(params SqlString[] p)
{
SqlString max=p[0];
foreach (string s in p)
max = s.CompareTo(max) > 0 ? s : max;

return max;

}
};

しかし、コンパイルまたはデプロイしようとすると、次のエラーが発生します。データ型SqlString[]が見つかりません。

SQL CLRを使用して私の要件を満たすことは可能ですか?

4

3 に答える 3

2

paramsいいえ、 T-SQL であろうと SQLCLR であろうと、SQL Server ユーザー定義関数で可変数のパラメーター (つまり、.NET の修飾子) を持つことはできません。はい、一部の組み込み関数はそのようなことを許可しますが (例: CHECKSUM(*))、それらは SQL Server に直接組み込まれており、ユーザー定義関数やテーブル値関数などの API には組み込まれていません。

この質問の目的を最もよく理解するために、どのような状況でこれらの値を取得していますか? それらはテーブルまたはクエリの複数の列ですか? それらはさまざまな行ですか?これらの値は既に CSV リストとして連結されていますか? 実際、T-SQL は、独自にリストを並べ替えるという非常に優れた機能を果たします。さまざまなシナリオでこれを行うために使用できるクエリを構造化してOUTER APPLY( FROM句の一部) 使用できる場合があります。例えば:

SELECT tab.name AS [TableName],
       ind.name AS [IndexName],
       col.name AS [ColumnName],
       greatest.Item AS [GREATEST()]
FROM   sys.tables tab
LEFT JOIN (sys.indexes ind
    INNER JOIN sys.index_columns indcol
            ON indcol.[object_id] = ind.[object_id]
           AND indcol.index_id = ind.index_id
    INNER JOIN sys.columns col
            ON col.[object_id] = indcol.[object_id]
           AND col.column_id = indcol.column_id
          )
       ON ind.[object_id] = tab.[object_id]
OUTER APPLY (SELECT TOP 1 tmp.Name AS [Item]
             FROM (
                    SELECT tab.name UNION ALL SELECT ind.name UNION ALL SELECT col.name
                  ) tmp(Name)
             ORDER BY tmp.Name ASC
            ) greatest

結果は、行ごとに 3 つの名前フィールドの中で「最大」の値になります。ご覧のとおり、この方法は柔軟で、任意の数の列を含めることができます。

于 2015-07-24T16:18:22.317 に答える
2

テーブル値関数を使用したソリューションは次のとおりです。

CREATE FUNCTION fn_Split
(
    @text VARCHAR(8000), 
    @delimiter VARCHAR(20) = ','
)
    RETURNS @Strings TABLE 
        (
            position INT IDENTITY PRIMARY KEY,
            value VARCHAR(8000)
        )
AS BEGIN
    DECLARE @index int
    SET @index = -1

    WHILE (LEN(@text) > 0) BEGIN
        -- Find the first delimiter
        SET @index = CHARINDEX(@delimiter , @text)

        -- No delimiter left?
        -- Insert the remaining @text and break the loop
        IF (@index = 0) AND (LEN(@text) > 0) BEGIN  
            INSERT INTO @Strings VALUES (LTRIM(RTRIM(@text)))
            BREAK 
        END 

        -- Found a delimiter
        -- Insert left of the delimiter and truncate the @text
        IF (@index > 1) BEGIN
            INSERT INTO @Strings VALUES (LTRIM(RTRIM(LEFT(@text, @index - 1))))
            SET @text = RIGHT(@text, (LEN(@text) - @index))
        END
        -- Delimiter is 1st position = no @text to insert
        ELSE SET @text = RIGHT(@text, (LEN(@text) - @index))
    END
    RETURN
END
GO

テスト:

DECLARE @test varchar(120)

SET @test = 'Abcd, Efgh, Zxy, EAD'

SELECT Top(1) value FROM dbo.fn_Split(@test, ',')
ORDER BY value DESC

GO

(ここから分割機能を変更)

: これは、これを行うための最速の方法ではないことはほぼ確実です。これを何百万回も実行する必要がある場合は、別のソリューションが適切な場合があります。

于 2010-05-24T05:45:21.190 に答える