我已经读过“如果你在sql中使用循环,你可能做错了”,这导致我在这里。在问题之前,关于场景的一些背景知识。我有以下数据库结构:
将GlobalSubmissions视为一个包含理想值的表,用户应该提交理想值。 UserSubmissions是一个包含用户提交的值的表。
我编写了一个函数,通过将用户的“提交”与单个特定的“globalSubmission”进行比较来估计用户的可靠性:
CREATE FUNCTION dbo.GetUserReliabilityForSubmission(@userID int, @submissionID int)
RETURNS float
AS
BEGIN
DECLARE @userAverageValue float,
@idealValue float;
SET @userAverageValue = (
SELECT AVG (Value)
FROM UserSubmissions
WHERE (UserID = @userID AND SubmissionID = @submissionID));
SET @idealValue = (
SELECT IdealValue
FROM Submission
WHERE (SubmissionID = @submissionID));
RETURN 1 - ABS(@userAverageValue - @idealValue);
END
这可以,但它只根据一个特定的提交ID计算用户的可靠性。如果我想计算用户的“全局”可靠性,我需要使用循环来浏览用户提交的所有不同 SubmissionID 并在其上运行该过程。
在这种情况下,使用循环是否有一个很好的替代方案?
答案 0 :(得分:2)
SELECT d.UserID, 1 - AVG(ABS(d.avg - d.IdealValue))
FROM (
SELECT us.UserID, gs.SubmissionID, gs.IdealValue, AVG(us.Value) as avg FROM UsersSubmissions us
JOIN GlobalSubmissions gs ON gs.SubmissionID = us.SubmissionID
GROUP BY us.UserID, gs.SubmissionID, gs.IdealValue) d
GROUP BY d.UserId
工作示例:http://sqlfiddle.com/#!6/8d880/8
但是,我认为这不是定义可靠性的好方法。我认为您应该考虑将其更改为:
SELECT d.UserID, 1 - AVG(ABS(d.avg - d.IdealValue) / ABS(d.IdealValue))
FROM (
SELECT us.UserID, gs.SubmissionID, gs.IdealValue, AVG(us.Value) as avg FROM UsersSubmissions us
JOIN GlobalSubmissions gs ON gs.SubmissionID = us.SubmissionID
GROUP BY us.UserID, gs.SubmissionID, gs.IdealValue) d
GROUP BY d.UserId
并举例:http://sqlfiddle.com/#!6/8d880/14
有什么变化?它将错误相对于值本身。说 x = 5 ,当它实际上是 6 并说 x = 500 时 501 之间有区别