如何将 Tsql 标量函数转换为表函数?

Posted

技术标签:

【中文标题】如何将 Tsql 标量函数转换为表函数?【英文标题】:How to convert a Tsql scalar function into a table function? 【发布时间】:2011-10-25 02:08:49 【问题描述】:

我正在使用 SSMS 2008,并且我有以下标量函数来获取文本字符串并从 Microsoft Word 中删除所有元标记。标签包含在“<...>”中,并且一列中可以有任意数量的标签/记录。

我创建了这个标量函数来更新该列中的每一行。

create function dbo.ufn_Striphtml
    (   @Input      varchar(max),
        @Delimiter  char(1)
    )
returns varchar(max)
as

begin

    declare @Output varchar(max)
    select  @Input = replace(replace(@input, '<', @Delimiter), '>', @Delimiter)

    select @Output = isnull(@Output, '') + s
    from    (    select   row_number() over (order by n.id asc) [i],
                 substring(@Delimiter + @Input + @Delimiter, n.id + 1, charindex(@Delimiter, @Delimiter + @Input + @Delimiter, n.id + 1) - n.id - 1) [s]
            from    [evolv_cs].[dbo].[progress_note] n
            where   n.id = charindex(@Delimiter, @Delimiter + @Input + @Delimiter, n.id) and
                 n.id <= len(@Delimiter + @Input)
            ) d
    where i % 2 = 1

    return @Output

end

如果 [progress_note] 有一个“id”int 列,这个标量函数就可以工作。但它没有,我也不能通过添加一个 int 列来修改这个表。所以问题是我试图在临时表上使用这个函数。

所以我尝试根据这个表创建一个视图,然后向它添加一个 PK int 列。因为当我尝试使用这个额外的 PK int 列(“id”)创建视图时,它给了我一个错误:

Msg 156, Level 15, State 1, Line 1
Incorrect syntax near the keyword 'identity'.

但 ALTER VIEW 不支持添加列。还有另一种方法可以做到这一点吗?这是我正在尝试修改的原始临时表:

select [progress_note].[note_text], [progress_note].[event_log_id]
INTO #TEMP_PN
from [evolv_cs].[dbo].[progress_note]
group by [progress_note].[event_log_id], [progress_note].[note_text]

[note_text] 是 varchar(max),event_log_id 是唯一标识符。所以 [note_text] 包含一堆“”字符。如何修改此函数以使其成为表函数?

当然,如果我在这个函数中尝试用#TEMP_PN 替换[progress_note] 表,它会出错,因为它无法识别它。那么如何针对我的情况修改这个函数呢?

同时,我开发了一个表格函数,它接受和输出表格参数。它不会出错,但也不会返回我希望的解析数据。缺少什么?

CREATE TYPE dbo.MyTableType AS TABLE 
(
    col1 int identity(1,1) NOT NULL,
    col2 varchar(max) NULL
)
GO

CREATE TABLE [dbo].[MyTable] (
    [col1] [int] identity(1,1) NOT NULL,
    [col2] [varchar](max) NULL
    )   
GO

create PROC usp_AddRowsToMyTable @MyTableParam MyTableType READONLY, @Delimiter varchar(30)
    as
    INSERT INTO MyTable([col2])
    SELECT [col2]   
    FROM @MyTableParam

    --update MyTable
    --set col2 = replace(replace(MyTable.col2, '<', @Delimiter), '>', @Delimiter)
    select s, i, t
    from(
    select MyTableInput.col1 [i],
    replace(replace(MyTable.col2, '<', @Delimiter), '>', @Delimiter) as t,
    substring(@Delimiter + MyTableInput.col2 + @Delimiter, MyTable.col1 + 1, 
    charindex(@Delimiter, @Delimiter + MyTableInput.col2 + @Delimiter, MyTable.col1 + 1) - MyTable.col1 - 1) [s]
    from MyTable
    inner join MyTable as MyTableInput on MyTable.col1 = MyTableInput.col1
    where MyTable.col1 = CHARINDEX(@Delimiter, @Delimiter + MyTableInput.col2 + @Delimiter, MyTable.col1)
     and MyTable.col1 <= LEN(@Delimiter + MyTableInput.col2)
) d


DECLARE @MyTable MyTableType

INSERT INTO @MyTable(col2)
VALUES ('<h><dsf>2000<h><dsf>'),
    ('<sd><dsf>2001'),
    ('2002<vnv><dsf>'),
    ('<gsd><dsf>2003<h><dsf>'),
    ('<eefs><dsf><h><dsf>2004<dfgd><dsf>')

EXEC dbo.usp_AddRowsToMyTable @MyTableParam = @MyTable, @Delimiter = '|'

【问题讨论】:

这个不存在的id 列应该是什么意思?在您的标量函数中,您将它与CHARINDEX 的结果以及LEN 的结果进行比较。该列代表什么类型的值?我的意思是,它不是“身份”意义上的 ID,是吗? 【参考方案1】:

不确定我是否理解您的问题,但您可以通过以下方式修改您的函数以使其返回一个表(称为表值函数):

create function dbo.ufn_StripHTML 
    (   @Input      varchar(max), 
        @Delimiter  char(1) 
    ) 
returns @retYourNewTable table
(
    id int primary key clustered not null,
    yoursecond column varchar(100) null,
    ....
) 
as
....

这是你要找的吗?

【讨论】:

OP 正在寻找该问题的功能解决方案,而不是句法解决方案。不要以为这就是他要找的东西。 卡什是正确的。我正在寻找一个功能性的解决方案。查看更新的说明。

以上是关于如何将 Tsql 标量函数转换为表函数?的主要内容,如果未能解决你的问题,请参考以下文章

TSQL 程序中无法识别 SQL 标量函数元素

sql 标量函数

从 TSQL 标量函数返回连接值

选择与表值函数连接中的 Oracle 标量函数

SQL Server标量函数将数字转换为带有序数的单词

Oracle学习标量函数