我有计算价格值的功能:
ALTER FUNCTION [dbo].[LAWI_DEinkauf](@sArtikelID varchar(36))
RETURNS NUMERIC(14, 2)
AS
BEGIN
DECLARE @menge DECIMAL(16,6)
DECLARE @tmenge DECIMAL(16,6)
DECLARE @wert DECIMAL(16,6)
DECLARE @ekpreis DECIMAL(16,6)
DECLARE @ekmenge DECIMAL(16,6)
DECLARE @myposI CURSOR
SET @ekpreis = 0
SET @ekmenge = 0
SET @wert = 0
SET @menge = 0
SET @tmenge = 0
SET @myposI = CURSOR SCROLL FOR
SELECT einkaufspreis, menge
FROM lawi_bewegung
WHERE artikelid = @sArtikelID
ORDER BY datum, ident;
OPEN @myposI
FETCH NEXT FROM @myposI INTO @ekpreis, @ekmenge
WHILE @@fetch_status = 0
BEGIN
SET @tmenge = @tmenge + @ekmenge
IF @ekpreis <> 0
SET @menge = @menge + @ekmenge
SET @wert = @wert + @ekpreis * @ekmenge
IF @tmenge = 0
SET @wert = 0
IF @tmenge = 0
SET @menge = 0
FETCH NEXT FROM @myposI INTO @ekpreis, @ekmenge;
END
CLOSE @myposI
DEALLOCATE @myposI
IF @menge = 0
SET @menge = 1
RETURN @wert / @menge
END
我尝试将此存储函数转换为带窗口函数的select。原因是存储函数在具有多行的选择中使用时性能较差。
通常情况如下:
(SELECT TOP 1
wert / CASE WHEN menge = 0 THEN 1 ELSE menge END
FROM
(SELECT
SUM(menge) OVER (ORDER BY datum, ident) as tmenge,
SUM(CASE WHEN einkaufspreis <> 0 THEN menge ELSE 0 END) OVER (ORDER BY datum, ident) AS menge,
SUM(einkaufspreis * menge) OVER (ORDER BY datum, ident) AS wert,
ROW_NUMBER() OVER (ORDER BY datum, ident) AS rn
FROM
lawi_bewegung
WHERE
artikelid = XXXX) a order by rn desc
在那里,XXXX将是参数sArtikelID
(在我的情况下来自外部选择)。
我的问题是存储函数的一部分,其中总和被重置:
IF @tmenge = 0
SET @wert = 0
IF @tmenge = 0
SET @menge = 0
如何将此逻辑包含在使用窗口函数的select中?
答案 0 :(得分:2)
以下查询似乎可以解决您的问题,但我不确定它是否会表现良好。你能用一些数据试试看并检查数值和性能吗?
WITH step1 AS (
SELECT
*,
CASE WHEN SUM(menge) OVER (PARTITION BY artikelid ORDER BY datum, ident) = 0 THEN 1 ELSE 0 END AS reset
FROM lawi_bewegung
),
step2 AS (
SELECT *,
SUM(reset) OVER (PARTITION BY artikelid ORDER BY datum, ident) - reset AS g
FROM step1
),
step3 AS (
SELECT artikelid,
SUM(CASE WHEN einkaufspreis <> 0 THEN menge ELSE 0 END)
OVER (PARTITION BY artikelid, g ORDER BY datum, ident) AS menge,
SUM(einkaufspreis * menge)
OVER (PARTITION BY artikelid, g ORDER BY datum, ident) AS wert,
ROW_NUMBER() OVER (PARTITION BY artikelid ORDER BY datum, ident) AS rn
FROM step2
)
SELECT i.artikelid,
d.*
FROM lawi_inventur i
CROSS APPLY (
SELECT TOP 1
CAST(wert / CASE WHEN menge = 0 THEN 1 ELSE menge END AS DECIMAL(14, 2)) AS DEinkauf
FROM step3 s
WHERE s.artikelid = i.artikelid
ORDER BY rn DESC
) d
;
它的工作方式如下:
reset
列上执行运行总和,从而有效地创建分组列。每次tmenge总和为0时,以下行将具有不同的分组值; 如果查看中间步骤的输出,可能会更容易理解。只需将最后一个SELECT(最后4行)更改为SELECT * from step1
或SELECT * FROM step2
,依此类推。
如果您为此查询提供了良好的索引,可能会有所帮助,类似于ON (artikelid, datum, ident) INCLUDE (menge, einkaufspreis)
。