【问题标题】:Subquery Returned More Than 1 Value with the Group By子查询返回超过 1 个值,分组依据
【发布时间】:2013-06-26 15:12:35
【问题描述】:

我在使用这些表和代码创建查询时遇到了一些问题, 我知道“GROUP BY Branch.BranchName”会导致获取多条记录,但是,如何避免这种情况并在单个查询中做到这一点。 我想要的是一张桌子 包含 BranchName -- 总 payedvalue -- 总 notpayedvalue

SELECT
    (
        SELECT SUM (DeptDesciption.DeptValue)
        FROM dbo.SudentPayments
            INNER JOIN dbo.Student ON dbo.SudentPayments.StudentId = dbo.Student.StudentId
            INNER JOIN dbo.DeptDesciption ON SudentPayments.DeptDesciptionId = DeptDesciption.DeptDesciptionId
            INNER JOIN dbo.Branch on dbo.Branch.BranchId = Student.BranchId
        WHERE SudentPayments.IsDeptPayed = 0
        GROUP BY Branch.BranchName
    ) AS Payed,
    (
        SELECT SUM (DeptDesciption.DeptValue)
        FROM dbo.SudentPayments
            INNER JOIN dbo.Student ON dbo.SudentPayments.StudentId = dbo.Student.StudentId
            INNER JOIN dbo.DeptDesciption ON SudentPayments.DeptDesciptionId = DeptDesciption.DeptDesciptionId
            INNER JOIN dbo.Branch on dbo.Branch.BranchId = Student.StudentId
        WHERE SudentPayments.IsDeptPayed = 1
        GROUP BY Branch.BranchName
    ) AS Notpayed,
    Branch.BranchName
FROM dbo.SudentPayments 
    INNER JOIN dbo.Student ON dbo.SudentPayments.StudentId = dbo.Student.StudentId
    INNER JOIN dbo.DeptDesciption ON SudentPayments.DeptDesciptionId = DeptDesciption.DeptDesciptionId
    INNER JOIN dbo.Branch on dbo.Branch.BranchId = Student.StudentId

【问题讨论】:

  • 首先要做的是完全停止使用相关子查询,因为它们是性能猪!请改用连接、派生表或 CTE。这是您需要打破的 SQL 反模式。

标签: sql sql-server


【解决方案1】:

试试这个 -

SELECT
      b.BranchName
    , Notpayed = SUM(CASE WHEN sp.IsDeptPayed = 1 THEN d.DeptValue END)
    , Payed = SUM(CASE WHEN sp.IsDeptPayed = 0 THEN d.DeptValue END)
FROM dbo.SudentPayments sp 
JOIN dbo.Student s ON sp.StudentId = s.StudentId
JOIN dbo.DeptDesciption d ON sp.DeptDesciptionId = d.DeptDesciptionId
JOIN dbo.Branch b on b.BranchId = s.StudentId
GROUP BY ALL b.BranchName

更新:

SELECT
      b.BranchName
    , Notpayed = ISNULL(t.Notpayed, 0)
    , Payed = ISNULL(t.Payed, 0)
FROM dbo.Branch b
LEFT JOIN (
     SELECT 
            s.StudentId
          , Notpayed = SUM(CASE WHEN sp.IsDeptPayed = 1 THEN d.DeptValue END)
          , Payed = SUM(CASE WHEN sp.IsDeptPayed = 0 THEN d.DeptValue END)
     FROM dbo.SudentPayments sp
     JOIN dbo.Student s ON sp.StudentId = s.StudentId
     JOIN dbo.DeptDesciption d ON sp.DeptDesciptionId = d.DeptDesciptionId
     GROUP BY s.StudentId
) t on b.BranchId = s.StudentId

【讨论】:

  • 非常感谢。但是这个查询只返回一个记录。但是我有多个 BranchName,除了这个它工作正常
  • 当我们考虑您的第一个和第二个查询时会影响性能
  • 这个需要看查询计划。但我认为第二个查询更可取。
【解决方案2】:

错误是不言自明的,在您的子查询中您返回多个结果,这是不允许的。如果您从逻辑上考虑如果有多行应该显示哪一行?

您遇到此问题的原因是,即使您已按 branch.BracnName 分组,您还没有链接回外部查询,因此您的子查询正在返回所有分支的结果。你需要类似的东西:

SELECT
    (
        SELECT SUM (dd.DeptValue)
        FROM dbo.SudentPayments sp
            INNER JOIN dbo.Student s ON dbo.sp.StudentId = s.StudentId
            INNER JOIN dbo.DeptDesciption dd ON sp.DeptDesciptionId = dd.DeptDesciptionId
        WHERE s.IsDeptPayed = 0
        AND s.BranchID = Branch.BranchID    -- LINK TO OUTER BRANCH TABLE
    ) AS Payed
FROM dbo.Branch

然而你的整个查询被重写如下,不需要相关的子查询,如果你可以避免相关的子查询,那么这通常是一个好主意。在某些 DBMS 中,优化器可以优化一些子查询并将它们转换为连接,但最简单的术语是相关子查询,您要求子查询对每一行执行一次,这会导致比使用连接更多的开销

SELECT  Branch.BranchName, 
        Payed = SUM(CASE WHEN SudentPayments.IsDeptPayed = 1 THEN DeptDesciption.DeptValue ELSE 0 END),
        Notpayed = SUM(CASE WHEN SudentPayments.IsDeptPayed = 0 THEN DeptDesciption.DeptValue ELSE 0 END)
FROM    dbo.SudentPayments
        INNER JOIN dbo.Student 
            ON dbo.SudentPayments.StudentId = dbo.Student.StudentId
        INNER JOIN dbo.DeptDesciption 
            ON SudentPayments.DeptDesciptionId = DeptDesciption.DeptDesciptionId
        INNER JOIN dbo.Branch 
            ON dbo.Branch.BranchId = Student.StudentId
GROUP BY Branch.BranchName;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-23
    • 2016-04-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多