表B中的结果来自表B的行数

时间:2016-05-04 16:40:45

标签: sql

我正在制作一份报告,该报告返回MEMBER表中加入日期范围的成员,关系(MEMBERS.relationship)列等于成员的'M',其成员类型是 THEN之一对于符合此条件的每个成员记录,我需要返回它们在CHKINS表中指定的时间段内的签到数。 CHKINS表中有一个条目用于每个签入,'缺血'字段需要设置为'真'才能成为有效签入。换句话说,John Doe在规定的时间内检查了10次。我需要返回一行指定的字段加上值“10”。我现在构建的内容为我提供了十行。

SELECT        
    EMPLOYEES.lname, EMPLOYEES.fname, 
    MEMBERS.fname AS Expr1, MEMBERS.scancode, MEMBERS.lname AS Expr2, 
    MEMBERTYPES.description, 
    MEMBERS.phone1, MEMBERS.phone2, MEMBERS.lastvisit, MEMBERS.email, 
    MEMBERS.datejoin, MEMBERS.dateexpire, MEMBERS.daterenewal, 
    CHKINS.checkin, SITES.sitename, MEMBERS.relationship, MEMBERS.mtypeid
FROM            
    MEMBERS 
INNER JOIN
    CHKINS ON MEMBERS.memid = CHKINS.memid 
INNER JOIN
    EMPLOYEES ON MEMBERS.employeeid = EMPLOYEES.employeeid 
INNER JOIN
    SITES ON MEMBERS.siteid = SITES.siteid 
INNER JOIN
    MEMBERTYPES ON MEMBERS.mtypeid = MEMBERTYPES.mtypeid
WHERE
    (CHKINS.ischeckin = 'True') 
    AND (CHKINS.checkin BETWEEN @rvStartDate AND DATEADD(day, 45, @rvStartDate)) 
    AND (MEMBERS.relationship = 'M') 
    AND (MEMBERS.status = 'A') 
    AND (MEMBERS.mtypeid = '1' OR MEMBERS.mtypeid = '10' OR
         MEMBERS.mtypeid = '12' OR MEMBERS.mtypeid = '22' OR
         MEMBERS.mtypeid = '28' OR MEMBERS.mtypeid = '32' OR
         MEMBERS.mtypeid = '33' OR MEMBERS.mtypeid = '34' OR
         MEMBERS.mtypeid = '35' OR MEMBERS.mtypeid = '36' OR
         MEMBERS.mtypeid = '40' OR MEMBERS.mtypeid = '48') 
    AND (MEMBERS.datejoin BETWEEN @rvStartDate AND @rvEndDate)

2 个答案:

答案 0 :(得分:1)

我不知道您的数据库架构的所有细节,但它似乎回答了您的问题,除非您希望报告中的其他列不需要某些联接。基本上,您希望使用带有计数的分组,它应该比您的子查询执行得快得多。在你的一条评论中看到你说你还在学习/相当新。我确实根据自己的口味改变了一些关于你的结构的事情。一个变化是我使用表缩写,例如。当你把表放在from区域时,只需添加一个空格,然后添加一个缩写(例如m代表成员)。另一个瘦是将mtypid的OR列表切换到一个基本上做同样事情的in语句。请注意,注释前面是 - 所以如果您在SSMS查询窗口中通过以下代码,您应该看到一些注释,我找到了使代码可读的有用提示。

使用group by并连接多个表时的技巧是了解一对一和一对一关系是什么。如果是一对多,例如在CHKINS表的情况下,这是你想要计算的,重要的是只使用一对一的其他表的成员表(例如membertypes)或使用count时确保你在计数中使用CHKINS的唯一id。鉴于您的问题没有询问在员工,膜类型或站点表中使用任何内容,您可以简单地删除它们,从而在成员和chckins之间留下直接的一对多关系。之后,对于您想要查看的关系一侧的所有列,包括组中的那些列。

SELECT        
    FirstName = m.fname  --m.fname AS Expr1 can chane to ,FirtsName = m.fname or ,m.fname AS FisrtName if you don't want Expr1
    ,LastName = m.lname  --m.lname AS Expr2 Again can replace Expr2 with something more meaninglfull if desired e.g. LastName (also is this exact same as e.lname ?  do you want both?)
    ,m.description
    ,m.phone1
    ,m.phone2
    ,m.lastvisit
    ,m.email
    ,m.datejoin
    ,m.dateexpire
    ,m.daterenewal
    ,m.relationship
    ,m.mtypeid
    ,m.status
    ,CountOfCheckins = COUNT(*)  --If you know the PrimaryKey for CHKINS you could aso do COUNT(DISNTINCT c.Id)
FROM            
    MEMBERS m
    INNER JOIN CHKINS c
    ON m.memid = c.memid 
    AND c.ischeckin = 'TRUE'
    --AND c.checkin BETWEEN @rvStartDate AND DATEADD(day, 45, @rvStartDate)  --only include if you want to also limit the checkins by the same date range
WHERE
    m.relationship = 'M'
    AND m.status = 'A' --if you want all statuses comment this line by adding -- in front
    AND m.mtypeid IN ('1','10','12','22','28','32','33','34','35','36','40','48')
    --AND m.mtypeid IN (1,10,12,22,28,32,33,34,35,36,40,48) --uncomment and use this line instead of above if m.mtypeid is a numeric data type (int, smallint, tinyint, etc.)
    AND m.datejoin BETWEEN @rvStartDate AND @rvEndDate
GROUP BY
    m.fname
    ,m.lname
    ,m.description
    ,m.phone1
    ,m.phone2
    ,m.lastvisit
    ,m.email
    ,m.datejoin
    ,m.dateexpire
    ,m.daterenewal
    ,m.relationship
    ,m.mtypeid
    ,m.status
ORDER BY
    m.fname
    ,m.lastname
    --this sorts list by First name then Last Name switch order if you want last first
    --or you can simply put CountOfCheckins to order by the least to greatest checkins or CountOfCheckins to get the greatest to the least

答案 1 :(得分:0)

您可以通过在选择列表中添加一个子查询来从CHKINS表中获取有效签到的计数,该子查询选择与MEMBERS.memid匹配的记录数,其中缺席为True

SELECT EMPLOYEES.lname
    ,EMPLOYEES.fname
    ,MEMBERS.fname AS Expr1
    ,MEMBERS.scancode
    ,MEMBERS.lname AS Expr2
    ,MEMBERTYPES.[description]
    ,MEMBERS.phone1
    ,MEMBERS.phone2
    ,MEMBERS.lastvisit
    ,MEMBERS.email
    ,MEMBERS.datejoin
    ,MEMBERS.dateexpire
    ,MEMBERS.daterenewal
    ,MEMBERS.relationship
    ,MEMBERS.mtypeid
    ,CHKINS.checkin
    ,SITES.sitename
    ,(SELECT COUNT(*) FROM CHKINS WHERE CHKINS.memid = MEMBERS.memid AND CHKINS.ischeckin = 'True') AS CheckinCount
FROM MEMBERS 
    INNER JOIN CHKINS ON MEMBERS.memid = CHKINS.memid
    INNER JOIN EMPLOYEES ON MEMBERS.employeeid = EMPLOYEES.employeeid
    INNER JOIN SITES ON MEMBERS.siteid = SITES.siteid 
    INNER JOIN MEMBERTYPES ON MEMBERS.mtypeid = MEMBERTYPES.mtypeid
WHERE (CHKINS.ischeckin = 'True')
    AND (CHKINS.checkin BETWEEN @rvStartDate AND DATEADD(day, 45, @rvStartDate)) 
    AND (MEMBERS.relationship = 'M') 
    AND (MEMBERS.[status] = 'A')
    AND (MEMBERS.mtypeid = '1' OR 
         MEMBERS.mtypeid = '10' OR
         MEMBERS.mtypeid = '12' OR
         MEMBERS.mtypeid = '22' OR
         MEMBERS.mtypeid = '28' OR
         MEMBERS.mtypeid = '32' OR
         MEMBERS.mtypeid = '33' OR
         MEMBERS.mtypeid = '34' OR
         MEMBERS.mtypeid = '35' OR
         MEMBERS.mtypeid = '36' OR
         MEMBERS.mtypeid = '40' OR
         MEMBERS.mtypeid = '48')
    AND (MEMBERS.datejoin BETWEEN @rvStartDate AND @rvEndDate)