Sql server 具有左联接/具有总和/分组依据的SQL Server

Sql server 具有左联接/具有总和/分组依据的SQL Server,sql-server,group-by,outer-join,having,Sql Server,Group By,Outer Join,Having,表B包含计划值。表M包含实际值。我需要找到表B中没有实际值的所有行,即表M中的连接行,或者连接行具有不同的总实际值行。我正在尝试外部联接和求和的组合。。。分组以实现这一点,但它不起作用,因为表B中的“孤立项”没有被返回 我的问题是:- SELECT B.Id, B.Date, b.Ref,SUM(M.Actual_Volume), SUM(B.Planned_Volume), SUM(M.Actual_Value),SUM(B.Planned_Value) FROM TableB B

表B包含计划值。表M包含实际值。我需要找到表B中没有实际值的所有行,即表M中的连接行,或者连接行具有不同的总实际值行。我正在尝试外部联接和求和的组合。。。分组以实现这一点,但它不起作用,因为表B中的“孤立项”没有被返回

我的问题是:-

 SELECT B.Id, B.Date, b.Ref,SUM(M.Actual_Volume), SUM(B.Planned_Volume),
 SUM(M.Actual_Value),SUM(B.Planned_Value)
 FROM
 TableB B
 left JOIN TableM M on M.Id = B.Id 
 inner JOIN TableX on TableX.FieldX = B.FieldX 
 WHERE TableX.FieldY = (SELECT T.FieldY from TableX T where T.FieldX = 408344)
 AND TableX.FieldZ = (SELECT T1.FieldZ from TableX T1 where T1.FieldX = 408344)
 group by B.Id, B.Date, B.Ref
 having SUM(M.Actual_Volume) <> SUM(B.Planned_Volume)
 OR SUM(M.Actual_Value) <> SUM(B.Planned_Value)
 order by b.Id
所以查询应该返回

 B.Id 
 53 (because planned_vol <> actual_vol and planned_val <> actual_val)
 61 (because B.Id 61 is not in table M)

这是未经测试的,但我认为您需要将having需求移到left-outer-join需求中。使用CTE,即您需要使用SQL Server 2005或更高版本才能工作,这是一种方法

having子句强制SQL Server将B-M联接视为内部联接。可能有另一种方法不使用CTE,即在所有正确的位置检查空值。但我更喜欢分而治之的方法

WITH
[BAlt] AS
(
    SELECT
        [B].[Id],
        [B].[Date],
        [B].[Ref],
        SUM([B].[Planned_Volume]) AS [Planned_Volume],
        SUM([B].[Planned_Value]) AS [Planned_Value],
    FROM [TableB] AS [B]
        INNER JOIN [TableX] AS [X1] ON [X1].[FieldX] = [B].[FieldX]
            AND [X1].[FieldY] =
            (
                SELECT
                    [X2].[FieldY]
                FROM [TableX] AS [X2]
                WHERE [X2].[FieldX] = 408344
            )
            AND [X1].[FieldZ] =
            (
                SELECT
                    [X3].[FieldZ]
                FROM [TableX] AS [X2]
                WHERE [X3].[FieldX] = 408344
            )
    GROUP BY
        [B].[Id],
        [B].[Date],
        [B].[Ref]
),
[MAlt] AS
(
    SELECT
        [M].[Id],
        SUM([M].[Actual_Volume]) AS [Actual_Volume],
        SUM([M].[Actual_Value]) AS [Actual_Value]
    FROM [M]
    GROUP BY
        [M].[Id]
)
SELECT
    [BAlt].[Id],
    [BAlt].[Date],
    [BAlt].[Ref],
    [BAlt].[Planned_Volume],
    [BAlt].[Planned_Value],
    [MAlt].[Actual_Volume],
    [MAlt].[Actual_Value]
FROM [BAlt]
    LEFT OUTER JOIN [MAlt] ON [MAlt].[Id] = [BAlt].[Id]
        AND
        (
            [MAlt].[Actual_Volume] <> [BAlt].[Planned_Volume]
                OR [MAlt].[Actual_Value] <> [BAlt].[Planned_Value]
        )
ORDER BY
    [BAlt].[Id]

我真的不觉得有什么问题:

    create table b
    (    B_id int
        ,PlannedVolume int
        ,PlannedValue int
    )

    create table M
    (    M_id int
        ,B_id int
        ,ActualVolume int
        ,ActualValue int
    )

    insert b (b_id, PlannedVolume, PlannedValue)
    values  (19, 2, 350),
        (28, 1, 100),
        (53, 3, 650),
        (61, 1, 50)

    insert m (m_id, b_id, ActualVolume, ActualValue)
    values  (58, 19, 2, 350),
        (65, 28, 1, 100),
        (66, 53, 1, 150),
        (67, 53, 1, 100)

   select b.b_id
   from b
     left join
     (  select b_id
            ,sum(ActualVolume) as ActualVolume
            ,sum(ActualValue) as ActualValue
        from m 
        group by b_id
     )   m       
     on  m.b_id = b.b_id
   where 
     m.b_id is null
     or
     (m.ActualValue <> b.PlannedValue and m.ActualVolume <> b.PlannedVolume)

能否为出于这两个原因希望返回的行和至少一个不希望返回的行显示一些示例数据。快速修复方法是将SUMM.Actual_Volume为null或SUMM.Actual_Value为null添加到having子句中,但我认为您正在尝试对n:m关系的两侧求和。这将导致数据重复。你能发布更多关于你的模式以及M和B之间关系的信息吗?是的,tableB到TableM是m:m,因为定义表是TableXI认为WHERE子句可以替换为这个连接:TableX.FieldY=T.FieldY和TableX.FieldZ=T.FieldZ,T.FieldX=408344或T.FieldX=408344可以移动到何处。我使用的是SQL Server 2005 9.00.1399.06,所以我将给出一个goDaniel,通过这种方式,将选择正确的集合作为SELECT子句,但由于某些原因,最终SELECT没有正确连接,并且为实际_Volume和实际_Value字段返回空值。有没有关于如何修复的想法?@epx-Actual\u-Volume和Actual\u-Value在ID存在于B中但不存在于M中的情况下将为null。如果您想要默认值,例如零,请在最终select子句中使用ISNULL[MAlt].[Actual\u-Volume],0和等效值作为实际\u-Value。问题是B和M之间不是1:1,在m中,你也可以得到第67,53,1100行。所以现在对于b_id 53,我们现在有一个未完成的计划_量1和一个未完成的计划_值400,这就是为什么我尝试分组。。。有总和,但还没有:-
    create table b
    (    B_id int
        ,PlannedVolume int
        ,PlannedValue int
    )

    create table M
    (    M_id int
        ,B_id int
        ,ActualVolume int
        ,ActualValue int
    )

    insert b (b_id, PlannedVolume, PlannedValue)
    values  (19, 2, 350),
        (28, 1, 100),
        (53, 3, 650),
        (61, 1, 50)

    insert m (m_id, b_id, ActualVolume, ActualValue)
    values  (58, 19, 2, 350),
        (65, 28, 1, 100),
        (66, 53, 1, 150),
        (67, 53, 1, 100)

   select b.b_id
   from b
     left join
     (  select b_id
            ,sum(ActualVolume) as ActualVolume
            ,sum(ActualValue) as ActualValue
        from m 
        group by b_id
     )   m       
     on  m.b_id = b.b_id
   where 
     m.b_id is null
     or
     (m.ActualValue <> b.PlannedValue and m.ActualVolume <> b.PlannedVolume)