【问题标题】:Sql Server 2008 r2 Using a WHILE loop inside a functionSql Server 2008 r2 在函数内使用 WHILE 循环
【发布时间】:2014-03-11 08:41:50
【问题描述】:

我读到一个回答说您不想在 SQL Server 中使用 WHILE 循环。我不明白这种概括。我对 SQL 还很陌生,所以我可能还不明白解释。我还读到除非必须,否则您并不想使用游标。我发现的搜索结果对所提出的问题过于具体,我无法从中收集到有用的技术,所以我将这个提供给您。

我要做的是获取客户端文件中的值并在必要时缩短它们。这里有几件事需要实现。我不能简单地破解提供的字段值。我的公司有要使用的标准缩写。我把这些放在一个表中,缩写。该表有LongNameShortName。我不想简单地缩写行中的每个LongName。只要字段长度太长,我只想应用更新。这就是我需要WHILE 循环的原因。

我的思考过程是这样的:

CREATE FUNCTION [dbo].[ScrubAbbrev]
(@Field nvarchar(25),@Abbrev nvarchar(255))
RETURNS varchar(255)
AS
BEGIN
    DECLARE @max int = (select MAX(stepid) from Abbreviations)
    DECLARE @StepID int = (select min(stepid) from Abbreviations)
    DECLARE @find varchar(150)=(select Longname from Abbreviations where Stepid=@stepid)
    DECLARE @replace varchar(150)=(select ShortName from Abbreviations where Stepid=@stepid)
    DECLARE @size int = (select max_input_length from FieldDefinitions where FieldName = 'title')
    DECLARE @isDone int = (select COUNT(*) from SizeTest where LEN(Title)>(@size))

    WHILE @StepID<=@max or @isDone = 0 and LEN(@Abbrev)>(@size) and @Abbrev is not null
    BEGIN
        RETURN
        REPLACE(@Abbrev,@find,@replace)
        SET @StepID=@StepID+1
        SET @find =(select Longname from Abbreviations where Stepid=@stepid)
        SET @replace =(select ShortName from Abbreviations where Stepid=@stepid)
        SET @isDone = (select COUNT(*) from SizeTest where LEN(Title)>(@size))
    END
END

显然RETURN 应该放在最后,但我需要将我的变量重置为下一个@stepID@find@replace

这是我必须使用光标(我还没有写过)的时候吗?

【问题讨论】:

    标签: sql sql-server function loops while-loop


    【解决方案1】:

    通常,您不想在 SQL 中使用游标或 while 循环,因为它们一次只处理一行,因此性能很差。 SQL 旨在处理(可能非常大)数据,而不是单个值。

    您可以通过执行以下操作来排除 while 循环:

    UPDATE t
    SET t.targetColumn = a.ShortName
    FROM targetTable t
    INNER JOIN Abbreviations a
    ON t.targetColumn = a.LongName
    WHERE LEN(t.targetColumn) > @maxLength
    

    这是通用的,您需要对其进行调整以适合您的特定数据模型,但实际情况如下:

    对于“targetTable”中的每一行,将“targetColumn”(您要缩写的)的值设置为相关缩写(在 Abbreviations.ShortName 中找到)iff:当前值具有标准化缩写(内连接)并且当前值比期望的长(where 条件)。

    您需要添加一个整数参数或局部变量@maxLength,以指示什么构成“过长”。此查询一次处理所有目标表,为每个符合条件的行更新目标列中的值,而函数一次只能找到单个项目的缩写(一行和一列的交集)。

    请注意,如果值太长但没有标准缩写,这将不起作用。您现有的代码也有同样的限制,所以我认为这是期望的行为。

    我还建议将此作为存储过程而不是函数。 SQL Server 上的函数被视为黑盒,会严重损害性能,因为优化器通常不知道它们在做什么。

    【讨论】:

    • 我明白你在说什么,因为任何必须评估每一行的事情都是一个繁重的过程。这是联系信息,因此我必须根据可用长度将其应用于每个字段。另外,我不能替换整个字段。我希望实现的目标是将“生物统计学研究副教授”转变为“UBC 病理学与实验室医学教授”,这就是为什么我使用REPLACE函数,而不是SET
    • 当然,有道理。看起来每个条目也可能有多个缩写。在这种情况下,您希望像 '%'+LongName+'%' 一样加入 targetColumn,并在更新语句中使用 replace。可能需要一些调整来确保避免误报(例如部分单词匹配),但一般技术是相同的:使用基于集合的方法来避免循环的性能问题。
    • 感谢您的帮助。下周我会重新审视这个项目。显然我还不能投票。 :-/
    • 干杯。一旦你收集了少量的声望,你就可以投票。您可以通过对您的问题和答案进行投票、接受答案或对他人的帖子进行编辑来做到这一点(但仅在必要时 - 您的编辑将由其他人审核并且必须获得批准)。
    猜你喜欢
    • 1970-01-01
    • 2018-10-28
    • 2014-02-10
    • 2011-05-28
    • 2013-08-18
    • 2010-12-25
    • 1970-01-01
    • 2014-11-10
    • 1970-01-01
    相关资源
    最近更新 更多