[英]Change an iterative query to a relational set-based query
我試圖將迭代/游標查詢(工作正常)更改為關系集查詢以實現更好的性能沒有成功。
我有的:
表格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的情況下實現相同目標。
如果問題是關於如何以面向集合的方式應用功能,那么cross apply
(或outer apply
)是您的朋友:
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 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 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)
)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.