Sql 将迭代查询更改为基于关系集的查询

Sql 将迭代查询更改为基于关系集的查询,sql,sql-server,tsql,Sql,Sql Server,Tsql,我试图将一个运行良好的迭代/游标查询更改为一个关系集查询以获得更好的性能,但没有成功 我所拥有的: 表1 |ID |名称| |--|---| |1 | A| |2 | B| |3 | C| 使用函数,我想将数据插入到另一个表中。以下函数是一个简化示例: 作用 创建函数fn_myExample函数 @输入nvarchar50 返回@ret_表 输出nvarchar50 像 开始 如果@input='A' 插入@ret_表值“Alice” 如果@input='B' 插入@ret_表值“Bob” 其

我试图将一个运行良好的迭代/游标查询更改为一个关系集查询以获得更好的性能,但没有成功

我所拥有的:

表1

|ID |名称| |--|---| |1 | A| |2 | B| |3 | C| 使用函数,我想将数据插入到另一个表中。以下函数是一个简化示例:

作用

创建函数fn_myExample函数 @输入nvarchar50 返回@ret_表 输出nvarchar50 像 开始 如果@input='A' 插入@ret_表值“Alice” 如果@input='B' 插入@ret_表值“Bob” 其他的 在@ret_表中插入值“Foo”、“Bar” 回来 终止 我的预期结果是在表2中插入数据,如下所示:

表2

|ID |名称| |--|----| |1 |爱丽丝| |2 |鲍勃| |3 | Foo| |3 |巴| 为了实现这一点,我尝试了一些CTEs通用表表达式和关系查询,但都没有达到预期效果。到目前为止,我得到的唯一有效的解决方案是一个迭代的而不是性能化的解决方案

我目前的工作方案:

开始 声明 @ID int, @i int=0, @max int=从表1中选择COUNTname 在本例中,@i<@max-将迭代3次 开始 设置@i+=1 -选择table1.ID,其中row_number=@i 设置@ID= 选择 身份证件 从…起 选择 身份证件 按id为rn的订单上的行号 从…起 表1行 哪里 rows.rn=@i -将与table1.ID相关的一行或多行插入table2 插入表2中 身份证,姓名 选择 @身份证, fn_结果输出 从…起 fn_MyExample函数 从表1中选择名称,其中id=@id fn_结果 终止 终止
我们的目标是在不遍历ID的情况下实现相同的功能。

这样的查询将实现您想要的功能:

insert into table2(id, name)
    select id, (case when name = 'A' then 'Alice'
                     when name = 'B' then 'Bob'
                     when name = 'C' then 'Foo'
                end)
    from table1
    union all
    select id, 'Bar'
    from table1
    where name = 'C';

这样的查询将满足您的要求:

insert into table2(id, name)
    select id, (case when name = 'A' then 'Alice'
                     when name = 'B' then 'Bob'
                     when name = 'C' then 'Foo'
                end)
    from table1
    union all
    select id, 'Bar'
    from table1
    where name = 'C';

如果问题是如何以面向集合的方式应用函数,那么交叉应用或外部应用是您的朋友:

insert into table2 (
    id, name
) select
   t1.id,
   t2.output
from
   table1 t1
       cross apply
   fn_myExampleFunction(t1.name) t2

如果函数的非简化版本可以重写,则其他解决方案可能会更快。

如果问题是如何以面向集合的方式应用函数,那么交叉应用或外部应用是您的朋友:

insert into table2 (
    id, name
) select
   t1.id,
   t2.output
from
   table1 t1
       cross apply
   fn_myExampleFunction(t1.name) t2

如果函数的非简化版本可以重写,那么其他解决方案可能会更快。

为什么不将此数据存储为表?这是关系型的。在函数或存储过程中对其进行编码似乎不太理想

在任何情况下,我希望以下内容都能为您提供有关如何改进代码的想法。我知道你说过你的函数比你的例子更复杂,但是你仍然可以根据需要在函数内部使用这个想法

INSERT dbo.table2 (ID, Name)
SELECT
   T1.ID,
   N.FullName
FROM
   dbo.table1 T1
   INNER JOIN (VALUES -- A "derived table" made up of only constants
      ('A', 'Alice'),
      ('B', 'Bob'),
      ('C', 'Foo'),
      ('C', 'Bar')
  ) N (ShortName, FullName)
      ON T1.Name = N.ShortName
;
但当然,如果它在一个真实的表中,则可以将其呈现为内部JOIN dbo.nametransformation N,然后更新它会容易得多

如果您的函数绝对不能重写为关系函数,则每次必须使用一个名称,然后您可以使用交叉应用:


但是,对于大型行集,这将无法很好地执行。将函数重写为返回表的类型是正确的步骤,而不是返回@variable TABLE definition。

为什么不将此数据存储为表?这是关系型的。在函数或存储过程中对其进行编码似乎不太理想

在任何情况下,我希望以下内容都能为您提供有关如何改进代码的想法。我知道你说过你的函数比你的例子更复杂,但是你仍然可以根据需要在函数内部使用这个想法

INSERT dbo.table2 (ID, Name)
SELECT
   T1.ID,
   N.FullName
FROM
   dbo.table1 T1
   INNER JOIN (VALUES -- A "derived table" made up of only constants
      ('A', 'Alice'),
      ('B', 'Bob'),
      ('C', 'Foo'),
      ('C', 'Bar')
  ) N (ShortName, FullName)
      ON T1.Name = N.ShortName
;
但当然,如果它在一个真实的表中,则可以将其呈现为内部JOIN dbo.nametransformation N,然后更新它会容易得多

如果您的函数绝对不能重写为关系函数,则每次必须使用一个名称,然后您可以使用交叉应用:


但是,对于大型行集,这将无法很好地执行。将函数重写为返回TABLE的类型是正确的一步,而不是返回@variable TABLE definition。

@Laurence,谢谢!我真正的功能是复杂的字符串拆分,您的建议更适合我。@Laurence,谢谢!我真正的功能是复杂的字符串拆分,你的建议更适合我。谢谢@ErikE。我真正的函数是复杂的字符串拆分,无法插入到表中,但基于我写的问题,这是一个很好的建议。投票支持你。如果你想提高速度,CLR可能是分割字符串的最佳选择。请看。谢谢你@ErikE。我真正的函数是复杂的字符串拆分,无法插入到表中,但基于我写的问题,这是一个很好的建议。投票支持你
。如果您正在寻找速度,CLR可能是拆分字符串的最佳选择。请看。