count()大于平均值

时间:2014-07-09 19:56:09

标签: sql sql-server

我试图解决以下SQL查询,它应该显示今年有更多问题的设备数据,而不是去年所有设备的平均问题数量和我;有点困惑。

到目前为止,我已经提出了这个问题:

select e.equipment_id ,
       e.equipment_name ,
       e.equipment_serialnum ,
       e.equipment_descrip
from equipment e ,
     problems  p
where e.equipment_id       = p.equipment_id
  and year( problem_date ) = year( getdate() )
group by e.equipment_id   ,
         e.equipment_name ,
         e.equipment_serialnum ,
         e.equipment_descrip
having count(p.problem_id) > ( select avg( pnumber )
                               from ( SELECT p1.problem_id ,
                                             COUNT( p1.problem_id ) AS pnumber
                                      FROM problems  p1
                                      JOIN equipment e1 ON e1.equipment_id = p1.equipment_id
                                                       and year( p1.problem_date ) = 2013
                                      GROUP BY p1.problem_id
                                    )

但它没有用。这是查询中涉及的表的结构

problems
(
  problem_id      integer  not null identity(1,1)
  equipment_id    integer  not null,
  user_id         integer  not null,
  problem_date    datetime not null,
  problem_descrip varchar(255)
)

equipment
(
  equipment_id        integer    not null identity(1,1) ,
  equipment_type_cod  char(20)   not null ,
  equipment_bought    datetime   not null ,
  equipment_available datetime   ,
  equipment_serialnum char(20)   ,
  equipment_name    varchar(255) ,
  equipment_descrip varchar(255)
)

感谢您提供的任何帮助。

2 个答案:

答案 0 :(得分:1)

您的子选择需要表名

( select avg( pnumber )
    from ( SELECT p1.problem_id ,
             COUNT( p1.problem_id ) AS pnumber
      FROM problems  p1
      JOIN equipment e1 ON e1.equipment_id = p1.equipment_id
                       and year( p1.problem_date ) = 2013
      GROUP BY p1.problem_id
    ) x
)

答案 1 :(得分:0)

首先,让我们创建我们的架构:

create table dbo.equipment
(
  equipment_id        integer      not null identity(1,1) primary key clustered ,
  equipment_type_cod  char(20)     not null ,
  equipment_bought    datetime     not null ,
  equipment_available datetime              ,
  equipment_serialnum char(20)              ,
  equipment_name      varchar(255)          ,
  equipment_descrip   varchar(255)          ,
)
go

create table dbo.problems
(
  problem_id      integer      not null identity(1,1) primary key clustered ,
  equipment_id    integer      not null foreign key references dbo.equipment( equipment_id ) ,
  user_id         integer      not null ,
  problem_date    datetime     not null ,
  problem_descrip varchar(255)          ,
)
go

将我们的问题分解为更小的离散块通常很有帮助。 SQL Server的with子句在这里很有用,因为它提供了一种定义名称虚拟表的便捷方法:

with
--
-- a 1-row table containing the starting date for the previous, current and next years
--
year_start as (
  select prev = convert(date,datename(year,dateadd(year, -1 , current_timestamp))) ,
         curr = convert(date,datename(year,dateadd(year,  0 , current_timestamp))) ,
         next = convert(date,datename(year,dateadd(year, +1 , current_timestamp)))
) ,
--
-- the count of problems per unit over the previous year. This
-- uses a left join to include those pieces of equipment that had no problems.
-- Depending on you requirement, you might want to change that to an inner join.
--
prev_year_problems as (
  select equipment_id = e.equipment_id ,
         problem_cnt  = coalesce( p.problems , 0 )
  from dbo.equipment e
  left join ( select equipment_id = p.equipment_id ,
                     problems     = count(*)
              from       dbo.problems p
              cross join year_start   y
              where p.problem_date >= y.prev
                and p.problem_date <  y.curr
              group by p.equipment_id
            ) p on p.equipment_id = e.equipment_id
) ,
--
-- the count of problems per unit in the current year, up to the current date.
-- This is essentially identical to the previous CTE, with the exception of
-- the boundaries of the desired date range.
--
curr_year_problems as (
  select equipment_id = e.equipment_id ,
         problem_cnt  = coalesce( p.problems , 0 )
  from dbo.equipment e
  left join ( select equipment_id = p.equipment_id ,
                     problems     = count(*)
              from       dbo.problems p
              cross join year_start   y
              where p.problem_date >= y.curr
                and p.problem_date <  y.next
              group by p.equipment_id
            ) p on p.equipment_id = e.equipment_id
) ,
--
-- Here, we roll the previous year's problem counts up and summarize them into
-- a single row table containing the mean number of problems per unit over the year.
--
previous_year_summary as (
  select mean_problems_per_unit = avg( t.problem_cnt )
  from prev_year_problems t
)
--
-- Finally, we select the rows from the equipment table that meet the defined
-- criteria
--
select e.* ,
       curr_year_problems_to_date       = cyp.problem_cnt ,
       prev_year_mean_problems_per_unit = ps.mean_problems_per_unit
from dbo.equipment         e
join curr_year_problems    cyp on cyp.equipment_id = e.equipment_id
join previous_year_summary ps  on cyp.problem_cnt > ps.mean_problems_per_unit