替代SQL中的“循环”?

时间:2013-03-16 11:12:15

标签: sql sql-server sql-server-2012

我已经读过“如果你在sql中使用循环,你可能做错了”,这导致我在这里。在问题之前,关于场景的一些背景知识。我有以下数据库结构:

  • “用户”具有:
    • UserID int IDENTITY(PK)
    • 可靠性浮动
  • “UserSubmissions”具有:
    • 价值浮动
    • UserID int(FK)(PK)
    • SubmissionID(FK)(PK)
    • 时间戳日期时间(PK)
  • “GlobalSubmissions”有:
    • IdealValue float
    • SubmissionID(PK)

将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 并在其上运行该过程。

在这种情况下,使用循环是否有一个很好的替代方案?

1 个答案:

答案 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 之间有区别