LEFT JOIN到表格一次,得到最小值和最大值

时间:2016-03-01 16:38:38

标签: sql sql-server-2012 ssms

这个问题的基本概念是我需要一个查询,它为我提供了一个独特的用户列表和我们正在寻找违规的日期。它显示了日期和用户,无论是否存在违规行为。日期表外部适用于用户始终显示用户的所有日期以及他们是否在该日期有违规。 例如:

UserID   Date    IsViolation
1         1/1      Y
1         1/2      Y
1         1/3      N
2         1/1      N
2         1/2      N
2         1/3      N

问题是我需要加入几个表来为这些用户产生违规行为。所以到目前为止看起来像这样:

SELECT u.ID AS UserID,
   u.FirstName,
   u.LastName,
   uc.ClientName,
   ul.LocationName,
   d.Date
FROM dbo.User AS u
JOIN dbo.UserClient AS uc ON u.ID = uc.UserID
JOIN dbo.UserLocation AS ul ON u.ID = ul.userID
OUTER APPLY #Dates
LEFT JOIN (
            SELECT uv.UserID,
               uv.ViolationID,
               uv.ViolationDate,
               v.ViolationName,
               vm.ViolationTypeID,
               uv.Date
            FROM dbo.UserViolation AS uv
            JOIN dbo.Violation AS v ON uv.ViolationID = v.ID
            JOIN dbo.ViolationMeta AS vm ON vm.ViolationID = v.ID
          ) AS v ON v.UserID = u.ID
             AND v.Date = d.Date

现在我将列出每个日期和用户的违规列表,如下所示:

UserID Date ViolationTypeID
1      1/1       1
1      1/1       2
1      1/1       3
1      1/2       NULL
1      1/3       1
2      1/1       NULL
etc....  

我需要根据ViolationTypeID和ViolationID将这些分组到特定的存储桶中。所以我想的是在同一个查询中做类似下面的事情:

SELECT u.ID AS UserID,
   u.FirstName,
   u.LastName,
   uc.ClientName,
   ul.LocationName,
   d.Date,
   MAX(CASE WHEN v.ViolationID IN (1,2,3) AND [ViolationTypeID] = 1 THEN 1 ELSE 0 END) AS [FormViolation]
   MAX(CASE WHEN v.ViolationTypeID IN (5,6,7) THEN 1 ELSE 0 END) AS [UrgentViolaion]
   MIN(CASE WHEN v.ID IS NOT NULL AND v.ViolationTypeID IN (1,2,3) THEN 0 ELSE 1 END) AS [NoViolation]
etc.....
GROUP BY u.ID,
       u.FirstName,
       u.LastName,
       uc.ClientName,
       ul.LocationName,
       d.Date

我试图点击表格只产生一次违规,而不是在表格的单独连接中为每个单独的场景命中它们。这对我来说似乎有点复杂,是否有更简单/更有效的方法来实现这一目标?

1 个答案:

答案 0 :(得分:0)

据我所知,您需要cross join来获取用户和日期。然后是left join违规和聚合。这有点复杂,因为违规日期是violations而不是userviolations(这对我来说真的没有意义),但是:

select u.id, d.date,
       (case when max(v.date) is null then 'N' else 'Y' end) as IsViolation
from dbo.User u cross join
     #dates d left join
     dbo.userviolation uv
     on u.id = uv.userid and
        d.date = uv.date
group by u.id, d.date;