从具有分组ID但未分组列中的差异的表中选择值

时间:2016-05-17 18:10:41

标签: sql sql-server tsql

我无法实现看起来应该简单的事情。下面的示例显示了在课程中注册的人员,一个人可以注册多个班级,但目前只有一个班级:

DECLARE @Test TABLE
(
  PersonId int NOT NULL,
  LocationId int NOT NULL,
  ClassId int NOT NULL,
  IsEnrolled bit NOT NULL,
  IsExited bit NOT NULL
)

添加数据:

INSERT INTO @Test
      SELECT 1,5,6,1,0
UNION SELECT 1,6,7,0,1
UNION SELECT 2,5,8,1,0
UNION SELECT 2,5,9,0,1
UNION SELECT 3,5,9,0,1
UNION SELECT 3,6,9,1,0

我想获取所有注册位于同一位置(具有相同LocationId)的人的所有记录(当前与否),但只有当前值(IsEnrolled = 1)所在的位置是不同的。 对于同一个PersonId,如果LocationId是唯一的,我想要所有记录,如果LocationId对于PersonId不是唯一的,则只有当前(IsEnrolled = 1)。

我希望从查询中获取数据:

SELECT       
     1 AS PersonId, 
     6 AS ClassId,
     1 As IsEnrolled, 
     0 AS IsExited
UNION SELECT 2, 8, 1, 0
UNION SELECT 2, 9, 0, 1
UNION SELECT 3, 9, 1, 0

5 个答案:

答案 0 :(得分:1)

以下是您可以使用的一种方法:

SELECT * 
FROM
(
    SELECT 
        *,
        (SELECT COUNT(DISTINCT t2.LocationID) FROM tab t2 WHERE t2.PersonId = t1.PersonId) AS LocationCount
    FROM tab t1
) t
WHERE 
    t.LocationCount = 1 --get all records for those at the same location
    OR (t.LocationCount > 1 AND t.IsEnrolled = 1) --get only current records for those @ multiple location

基本上,您可以计算某人注册的位置。如果它们只是一个,则记录所有记录,如果多个只记录当前的记录。

答案 1 :(得分:1)

我认为它比以前尝试的方法简单得多:

SELECT Test.*
FROM @Test Test
JOIN
    (
        SELECT PersonID, LocationID
        FROM @Test T
        WHERE ISENROLLED = 1
        GROUP BY PeronID, LocationID
    ) T
    ON Test.PersonID = T.PersonID
    AND Test.LocationID = T.LocationID

因为你只能有一个" isenrolled"每人记录,内部查询保证为每个人返回一个人/位置组合。因此,在人员和位置上加入它可以确保您获得当前注册课程所在位置的每个人的记录。

答案 2 :(得分:1)

如果我理解正确,您希望所有记录都是最新的或属于一直位于同一位置的人。因此:

select personid, classid, isenrolled, isexited
from mytable
where isenrolled = 1
or personid in
(
  select personid
  from mytable
  group by personid
  having min(locationid) = max(locationid)
)
order by personid, classid;

与窗口函数相同,因此必须只读取一次表:

select personid, classid, isenrolled, isexited
from
(
  select 
    personid, classid, isenrolled, isexited,
    min(locationid) over (partition by personid) as minloc,
    max(locationid) over (partition by personid) as maxloc
  from mytable
)
where isenrolled = 1 or minloc = maxloc
order by personid, classid;

答案 3 :(得分:0)

您可以使用聚合查询获取personid

select personid
from @test t
where isenrolled = 1
group by personid
having min(location) = max(location);

此时,使用in来获取其他所有内容非常容易:

select t.*
from @test t
where personid in (select personid
                   from @test t
                   where isenrolled = 1
                   group by personid
                   having min(location) = max(location)
                  );

答案 4 :(得分:0)

一次加入

select t2.PersonId, t2.ClassId, t2.IsEnrolled, t2.IsExited
    from @Test t1
        left join @Test t2
            on t2.PersonId = t1.PersonId
                and ((t2.IsEnrolled = 0 and t2.LocationId <> t1.LocationId)
                    or (t2.IsEnrolled = 1)
                )
    where t1.IsEnrolled = 1