是否可以用 CTE 替换用作标量值的子查询?
Is it possible to replace sub-queries, used as a scalar value, with CTE?
我想用一个短别名替换一个 return 标量值或不存在的长子查询,因为我将它放在 UPDATE 语句中 3 次。子查询取 UncoveredLoss
中的最后一个值,如果有的话,根据最后一个 UncoveredLoss
值在更新的行中计算新的 UncoveredLoss
值。
是非关联查询,但是用在SELECT
子句中,而不是在FROM
子句中。也许我应该以某种方式修改触发器中的 UPDATE
语句。
工作代码:
CREATE TRIGGER Result
UPDATE OF Win ON Log
BEGIN
UPDATE Log
SET Profit = CASE
WHEN NEW.Win = 0
THEN - Stake
WHEN NEW.Win = 1
THEN Rate * Stake / 100
WHEN NEW.Win = 2
THEN 0
END
WHERE ID = OLD.ID;
UPDATE Log
SET SumProfit = (
SELECT Sum(Profit)
FROM (
SELECT StrategyAccountID
,Profit
FROM Log
WHERE DATE <= NEW.DATE
)
GROUP BY StrategyAccountID
HAVING StrategyAccountID = NEW.StrategyAccountID
)
WHERE ID = NEW.ID;
UPDATE Log
SET UncoveredLoss = CASE
WHEN EXISTS (
SELECT UncoveredLoss
FROM Log
WHERE DATE < NEW.DATE
AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY DATE DESC LIMIT 1
)
AND (
SELECT UncoveredLoss
FROM Log
WHERE DATE < NEW.DATE
AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY DATE DESC LIMIT 1
) + NEW.Profit < 0
THEN (
SELECT UncoveredLoss
FROM Log
WHERE DATE < NEW.DATE
AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY DATE DESC LIMIT 1
) + NEW.Profit
WHEN NOT EXISTS (
SELECT UncoveredLoss
FROM Log
WHERE DATE < NEW.DATE
AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY DATE DESC LIMIT 1
)
AND NEW.Profit < 0
THEN NEW.Profit
ELSE 0
END
WHERE ID = NEW.ID;
END;
使用 CTE 简单替换子查询不起作用:
CREATE TRIGGER Result
UPDATE OF Win ON Log
BEGIN
UPDATE Log
SET Profit = CASE
WHEN NEW.Win = 0
THEN - Stake
WHEN NEW.Win = 1
THEN Rate * Stake / 100
WHEN NEW.Win = 2
THEN 0
END
WHERE ID = OLD.ID;
UPDATE Log
SET SumProfit = (
SELECT Sum(Profit)
FROM (
SELECT StrategyAccountID
,Profit
FROM Log
WHERE DATE <= NEW.DATE
)
GROUP BY StrategyAccountID
HAVING StrategyAccountID = NEW.StrategyAccountID
)
WHERE ID = NEW.ID;
WITH Loss
AS (
SELECT UncoveredLoss
FROM Log
WHERE DATE < NEW.DATE
AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY DATE DESC LIMIT 1
)
UPDATE Log
SET UncoveredLoss = CASE
WHEN EXISTS (Loss)
AND (Loss) + NEW.Profit < 0
THEN (Loss) + NEW.Profit
WHEN NOT EXISTS (Loss)
AND NEW.Profit < 0
THEN NEW.Profit
ELSE 0
END
WHERE ID = NEW.ID;
END;
Error: near "UPDATE": syntax error
当我不替换子查询时它工作得很好,但是当我尝试使用 CTE 时它失败了。我在 Emacs 中以 sql.el 模式工作。
是的,可以清理很多。考虑这样的事情:
CREATE TRIGGER Result UPDATE OF Win ON Log BEGIN
UPDATE Log
SET SumProfit = (SELECT sum(Profit)
FROM Log
WHERE Date <= NEW.Date AND StrategyAccountID = NEW.StrategyAccountID)
, UncoveredLoss = ifnull((SELECT min(UncoveredLoss + NEW.Profit, 0)
FROM Log
WHERE Date < NEW.Date AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY Date DESC
LIMIT 1), 0)
WHERE ID = NEW.ID;
END;
我很确定计算的结果与您的相同。 (实际样本 table 定义和数据会很好)
另请注意,在最近的 Sqlite3 版本(3.25 及更高版本)中,您的 SumProfit
列可以很容易地按需计算,而不是占用 table 中的 space:
SELECT *
, sum(profit) OVER (PARTITION BY StrategyAccountID ORDER BY Date) AS SumProfit
FROM Log;
我想用一个短别名替换一个 return 标量值或不存在的长子查询,因为我将它放在 UPDATE 语句中 3 次。子查询取 UncoveredLoss
中的最后一个值,如果有的话,根据最后一个 UncoveredLoss
值在更新的行中计算新的 UncoveredLoss
值。
是非关联查询,但是用在SELECT
子句中,而不是在FROM
子句中。也许我应该以某种方式修改触发器中的 UPDATE
语句。
工作代码:
CREATE TRIGGER Result
UPDATE OF Win ON Log
BEGIN
UPDATE Log
SET Profit = CASE
WHEN NEW.Win = 0
THEN - Stake
WHEN NEW.Win = 1
THEN Rate * Stake / 100
WHEN NEW.Win = 2
THEN 0
END
WHERE ID = OLD.ID;
UPDATE Log
SET SumProfit = (
SELECT Sum(Profit)
FROM (
SELECT StrategyAccountID
,Profit
FROM Log
WHERE DATE <= NEW.DATE
)
GROUP BY StrategyAccountID
HAVING StrategyAccountID = NEW.StrategyAccountID
)
WHERE ID = NEW.ID;
UPDATE Log
SET UncoveredLoss = CASE
WHEN EXISTS (
SELECT UncoveredLoss
FROM Log
WHERE DATE < NEW.DATE
AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY DATE DESC LIMIT 1
)
AND (
SELECT UncoveredLoss
FROM Log
WHERE DATE < NEW.DATE
AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY DATE DESC LIMIT 1
) + NEW.Profit < 0
THEN (
SELECT UncoveredLoss
FROM Log
WHERE DATE < NEW.DATE
AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY DATE DESC LIMIT 1
) + NEW.Profit
WHEN NOT EXISTS (
SELECT UncoveredLoss
FROM Log
WHERE DATE < NEW.DATE
AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY DATE DESC LIMIT 1
)
AND NEW.Profit < 0
THEN NEW.Profit
ELSE 0
END
WHERE ID = NEW.ID;
END;
使用 CTE 简单替换子查询不起作用:
CREATE TRIGGER Result
UPDATE OF Win ON Log
BEGIN
UPDATE Log
SET Profit = CASE
WHEN NEW.Win = 0
THEN - Stake
WHEN NEW.Win = 1
THEN Rate * Stake / 100
WHEN NEW.Win = 2
THEN 0
END
WHERE ID = OLD.ID;
UPDATE Log
SET SumProfit = (
SELECT Sum(Profit)
FROM (
SELECT StrategyAccountID
,Profit
FROM Log
WHERE DATE <= NEW.DATE
)
GROUP BY StrategyAccountID
HAVING StrategyAccountID = NEW.StrategyAccountID
)
WHERE ID = NEW.ID;
WITH Loss
AS (
SELECT UncoveredLoss
FROM Log
WHERE DATE < NEW.DATE
AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY DATE DESC LIMIT 1
)
UPDATE Log
SET UncoveredLoss = CASE
WHEN EXISTS (Loss)
AND (Loss) + NEW.Profit < 0
THEN (Loss) + NEW.Profit
WHEN NOT EXISTS (Loss)
AND NEW.Profit < 0
THEN NEW.Profit
ELSE 0
END
WHERE ID = NEW.ID;
END;
Error: near "UPDATE": syntax error
当我不替换子查询时它工作得很好,但是当我尝试使用 CTE 时它失败了。我在 Emacs 中以 sql.el 模式工作。
是的,可以清理很多。考虑这样的事情:
CREATE TRIGGER Result UPDATE OF Win ON Log BEGIN
UPDATE Log
SET SumProfit = (SELECT sum(Profit)
FROM Log
WHERE Date <= NEW.Date AND StrategyAccountID = NEW.StrategyAccountID)
, UncoveredLoss = ifnull((SELECT min(UncoveredLoss + NEW.Profit, 0)
FROM Log
WHERE Date < NEW.Date AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY Date DESC
LIMIT 1), 0)
WHERE ID = NEW.ID;
END;
我很确定计算的结果与您的相同。 (实际样本 table 定义和数据会很好)
另请注意,在最近的 Sqlite3 版本(3.25 及更高版本)中,您的 SumProfit
列可以很容易地按需计算,而不是占用 table 中的 space:
SELECT *
, sum(profit) OVER (PARTITION BY StrategyAccountID ORDER BY Date) AS SumProfit
FROM Log;