SQL左联接求和一对一

时间:2018-10-25 20:31:31

标签: sql-server

我试图从具有一对多关系的两个不同但相关的表中获取SUM,但是当我在第二个表中添加where条件时,第一个表不能正确地求和。可以在单个查询中完成吗?我还应注意,至关重要的是,它们都应考虑来自外部过滤器的相同的LocationId集。如果可能,我还需要在连接后发生Activityname条件。如果那不可能,那很好。

IF OBJECT_ID('tempdb..#tmpVisits') is not null
begin
    drop TABLE #tmpVisits
end

IF OBJECT_ID('tempdb..#tmpVisitsByActivity') is not null
begin
    drop TABLE #tmpVisitsByActivity
end


CREATE TABLE #tmpVisits
(
    AccountId int,
    LocationId int,
    Dt DATE,
    TotalVisits int
)

CREATE TABLE #tmpVisitsByActivity
(
    AccountId int,
    LocationId int, 
    EventDate DATE,
    TotalCompleted INT,
    ActivityName varchar(20)
)

insert INTO #tmpVisits
SELECT 1,10,'2018-09-12',12
union ALL
SELECT 1,11,'2018-09-12',20
union ALL
SELECT 1,22,'2018-09-12',10

insert INTO #tmpVisitsByActivity
SELECT 1,10,'2018-09-12',55,'ActivityA'
union ALL
SELECT 1,10,'2018-09-12',1,'ActivityA'
union ALL
SELECT 1,10,'2018-09-12',2,'ActivityB'
union ALL
SELECT 1,22,'2018-09-12',3,'ActivityC'

SELECT SUM(v.TotalVisits) --expecting 42 actual 10
, SUM(a.TotalCompleted) --expecting 3 actual 3
FROM #tmpVisits v
left JOIN #tmpVisitsByActivity a
ON v.AccountId = a.AccountId
AND v.dt = a.EventDate
AND v.LocationId = a.locationid
WHERE v.dt='2018-09-12' AND v.AccountId=1 
AND a.ActivityName='ActivityC'

2 个答案:

答案 0 :(得分:0)

最后一个条件使得没有匹配项时,将排除#tmpVisits中的某些条件。

但这很容易解决。

将a.ActivityName的条件移至ON子句,并将其从WHERE子句中删除。

...
LEFT JOIN #tmpVisitsByActivity a 
  ON a.AccountId = v.AccountId AND
     a.EventDate = v.dt AND
     a.LocationId = v.locationId AND
     a.ActivityName = 'ActivityA'
WHERE v.dt = '2018-09-12' 
  AND v.AccountId = 1

但是最好将第二个表放在子查询中。否则第一个SUM可能是错误的。

示例片段:

DECLARE @Visits TABLE
(
    AccountId INT,
    LocationId INT,
    Dt DATE,
    TotalVisits INT
);

DECLARE @VisitsByActivity TABLE
(
    AccountId INT,
    LocationId INT, 
    EventDate DATE,
    TotalCompleted INT,
    ActivityName VARCHAR(20)
);

INSERT INTO @Visits (AccountId, LocationId, Dt, TotalVisits) VALUES
(1,10,'2018-09-12',12),
(1,11,'2018-09-12',20),
(1,22,'2018-09-12',10);

INSERT INTO @VisitsByActivity (AccountId, LocationId, EventDate, TotalCompleted, ActivityName) VALUES 
(1,10,'2018-09-12',55,'ActivityA'),
(1,10,'2018-09-12',1,'ActivityA'),
(1,10,'2018-09-12',2,'ActivityB'),
(1,22,'2018-09-12',1,'ActivityC'),
(1,22,'2018-09-12',2,'ActivityC');

SELECT 
 SUM(v.TotalVisits) AS TotalVisits,
 SUM(ac.TotalCompleted) AS TotalCompleted
FROM @Visits v
LEFT JOIN 
(
   SELECT AccountId, EventDate, locationid, 
    SUM(TotalCompleted) AS TotalCompleted
   FROM @VisitsByActivity
   WHERE ActivityName = 'ActivityC'
   GROUP BY AccountId, EventDate, locationid
) AS ac
ON (ac.AccountId = v.AccountId AND ac.EventDate = v.dt AND ac.LocationId = v.locationid)
WHERE v.dt = '2018-09-12' 
  AND v.AccountId=1 

答案 1 :(得分:0)

如果要使用单个查询,则可以在where条件中移动join条件子句,如下所示。

SELECT SUM(v.TotalVisits) --expecting 42 actual 10
, SUM(a.TotalCompleted) --expecting 3 actual 3
FROM #tmpVisits v
left JOIN #tmpVisitsByActivity a
ON v.AccountId = a.AccountId
AND v.dt = a.EventDate
AND v.LocationId = a.locationid
AND v.dt='2018-09-12' AND v.AccountId=1 
AND a.ActivityName='ActivityC'