我正在尝试将迭代/游标查询(工作正常)更改为关系集查询以获得更好的性能。
我有什么:
表1
| ID | NAME |
|----|------|
| 1 | A |
| 2 | B |
| 3 | C |
使用函数,我想将我的数据插入另一个表。以下函数是一个简化示例:
功能
CREATE FUNCTION fn_myExampleFunction
(
@input nvarchar(50)
)
RETURNS @ret_table TABLE
(
output nvarchar(50)
)
AS
BEGIN
IF @input = 'A'
INSERT INTO @ret_table VALUES ('Alice')
ELSE IF @input = 'B'
INSERT INTO @ret_table VALUES ('Bob')
ELSE
INSERT INTO @ret_table VALUES ('Foo'), ('Bar')
RETURN
END;
我期望的结果是在table2中插入数据,如下所示:
表2
| ID | NAME |
|----|-------|
| 1 | Alice |
| 2 | Bob |
| 3 | Foo |
| 3 | Bar |
为了实现这一点,我尝试了一些CTE(公用表表达式)和关系查询,但没有一个按预期工作。到目前为止,我唯一可行的解决方案是迭代而非性能解决方案。
我目前的工作解决方案:
BEGIN
DECLARE
@ID int,
@i int = 0,
@max int = (SELECT COUNT(name) FROM table1)
WHILE ( @i < @max ) -- In this example, it will iterate 3 times
BEGIN
SET @i += 1
-- Select table1.ID where row_number() = @i
SET @ID =
(SELECT
id
FROM
(SELECT
id,
ROW_NUMBER() OVER (ORDER BY id) as rn
FROM
table1) rows
WHERE
rows.rn = @i
)
-- Insert into table2 one or more rows related with table1.ID
INSERT INTO table2
(id, name)
SELECT
@ID,
fn_result.output
FROM
fn_myExampleFunction (
(SELECT name FROM table1 WHERE id = @ID)
) fn_result
END
END
目标是在不重复ID的情况下实现相同目标。
答案 0 :(得分:2)
如果问题是关于如何以面向集合的方式应用函数,那么cross apply
(或outer apply
)就是你的朋友:
insert into table2 (
id, name
) select
t1.id,
t2.output
from
table1 t1
cross apply
fn_myExampleFunction(t1.name) t2
如果您的功能的非简化版本适合重写,其他解决方案可能会更快。
答案 1 :(得分:1)
这样的查询可以满足您的需求:
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';
答案 2 :(得分:1)
为什么不将这些数据存储为表格?它是关系型的。在函数或存储过程中对其进行编码似乎不太理想。
无论如何,我希望以下内容为您提供有关如何改进代码的建议。我意识到你说你的函数比你的例子更复杂,但你仍然可以在函数内部使用这个想法。
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
;
但是,当然,如果它在真实的表中,那么它可以被渲染INNER JOIN dbo.NameTranslation N
(然后更新它会更容易!)。
如果您的功能绝对不能被重写为关系(一次只能使用一个名称),那么您将使用CROSS APPLY
:
INSERT dbo.table2 (ID, Name)
SELECT
T1.ID,
N.OutputName
FROM
dbo.table1 T1
CROSS APPLY dbo.YourFunction(T1.Name) F
;
但是,对于大型行集,这不会很好。将函数重写为RETURNS TABLE
在正确方向上的步骤(而不是RETURNS @variable TABLE (definition)
)的类型。