简单的SQL Server COUNT查询(计算列中值的更改)

时间:2012-01-08 16:08:08

标签: sql sql-server count

我有一个包含列的表:MONTHYEARPROJECT_IDSTATUS

状态可以是:

  • R (红色)。
  • A (琥珀色)。
  • G (绿色)。
  • N (未开始)。
  • C (已完成)。

我想知道在某个月内完成了多少个项目,即:

where STATUS changed from anything that is NOT C to C;

听起来很简单......!

当任何给定项目完成时,很容易找到:

SELECT TOP 1 MONTH,YEAR,PROJECT_ID FROM Table WHERE PROJECT_ID=9236 AND RAG='C'
  ORDER BY YEAR ASC, MONTH ASC

但是考虑到year = 2011month = 8(例如),我不知道如何找到当月第一次拥有status='C'的项目数量。有什么想法吗?

编辑项目在完成后仍然包含status='C'行,因此我无法计算Cs,因为这将返回已完成项目的数量这个和前几个月(因此按时间顺序排列并选择前1个)。

2010年10月至2011年1月的样本数据:

Month | Year | Project | Status
-------------------------------
10    | 2010 | A       | G
11    | 2010 | A       | C
12    | 2010 | A       | C
1     | 2011 | A       | C
10    | 2010 | B       | R
11    | 2010 | B       | R
12    | 2010 | B       | R
1     | 2011 | B       | R
10    | 2010 | C       | G
11    | 2010 | C       | G
12    | 2010 | C       | G
1     | 2011 | C       | C
10    | 2010 | D       | A
11    | 2010 | D       | C
12    | 2010 | D       | C
1     | 2011 | D       | C

^项目A和D于2010年11月完成。项目B在所示的四个月中的任何一个月内都没有改变。项目C于2011年1月完成。 {Month,Year,Project}是主键。

因此,输入和输出将是:

10/2010 => 0
11/2010 => 2 (because of A and D)
12/2010 => 0
1/2011 => 1 (because of C)

4 个答案:

答案 0 :(得分:1)

SELECT 
   distinctMonths.month, 
   distinctMonths.year, 
   count(countProjects.project) as numChanges
FROM
  (
  SELECT DISTINCT
    month, year
  FROM
   Table
  ) as distinctMonths -- need to get all months available, independent of the project status, in case there were not an complete ones during a given month
    LEFT OUTER JOIN
    (
      SELECT
        Month, Year, Project
      FROM
        Table
      WHERE
        status = 'C' AND
        NOT EXISTS ( -- this will filter out our result set to only include the earliest instance of the given project's complete status
          SELECT 
            1 
          FROM 
            Table t2 
          WHERE 
            t2.project = Table.project AND
            t2.status = 'C' AND
            ( -- this will convert the date fragments into proper date values, that can be compared easily
                cast(
                    cast(t2.year as varchar) + '-' + cast(t2.month as varchar) + '-1'
                as datetime) 
                < 
                cast(
                    cast(table.year as varchar) + '-' + cast(table.month as varchar) + '-1'
                as datetime) 
            )

        )

    ) as countProjects ON
      distinctMonths.month = countProjects.month AND
      distinctMonths.year = countProjects.year
GROUP BY
   distinctMonths.month, 
   distinctMonths.year
ORDER BY
  distinctMonths.year,
  distinctMonths.month

答案 1 :(得分:1)

这将为您提供您正在寻找的计数

select p1.mm,p1.yyyy,COUNT(*)
from projs p1
join (select projid,MIN(yyyy*100+mm) as closedOn from projs 
      where stat='c' group by projId) xx 
      on xx.projId=p1.projId and p1.yyyy*100+p1.mm=xx.closedOn
where p1.stat='c' 
group by p1.mm,p1.yyyy

内部查询确定项目关闭的日期,因此您将查找本月关闭的所有项目......

答案 2 :(得分:1)

你去了

WITH 
src(month, year, project, status) AS (
    SELECT 10,2010,'A','G' UNION ALL
    SELECT 11,2010,'A','C' UNION ALL
    SELECT 12,2010,'A','C' UNION ALL
    SELECT 1,2011,'A','C' UNION ALL
    SELECT 10,2010,'B','R' UNION ALL
    SELECT 11,2010,'B','R' UNION ALL
    SELECT 12,2010,'B','R' UNION ALL
    SELECT 1,2011,'B','R' UNION ALL
    SELECT 10,2010,'C','G' UNION ALL
    SELECT 11,2010,'C','G' UNION ALL
    SELECT 12,2010,'C','G' UNION ALL
    SELECT 1,2011,'C','C' UNION ALL
    SELECT 10,2010,'D','A' UNION ALL
    SELECT 11,2010,'D','C' UNION ALL
    SELECT 12,2010,'D','C' UNION ALL
    SELECT 1,2011,'D','C'),
src_date (date, project, status) AS (   
    SELECT date = CONVERT(DATETIME, CONVERT(VARCHAR, year * 100 + month) + '01'), project, status
    FROM src
)
SELECT month = CONVERT(VARCHAR, YEAR(alldates.date)) + '/' + CONVERT(VARCHAR, MONTH(alldates.date)), 
       projects = ISNULL(cnt.value,0)
FROM (
    SELECT DISTINCT date
    FROM src_date
) alldates
LEFT JOIN 
(
    SELECT date = min_date, value = COUNT(*)
    FROM 
    (
        SELECT project, min_date = MIN(date)
        FROM src_date
        WHERE status = 'C'
        GROUP BY project
    ) mins
    GROUP BY min_date
) cnt
ON alldates.date = cnt.date

答案 3 :(得分:1)

我喜欢使用这个函数:lead()over()。 例如,如果你有这个选择:

select Month, Year, Project, Status
from youTable
where 1 = 1 --if you have any condition

我使用lead()函数找到“status”列的下一个值,并将其与当前值进行比较:

select count(1) as number from
   (select lead(Status) over(order by Project) as nextStatus,  Month, Year, Project, Status
    from youTable
    where 1=1) as tmp
where tmp.nextStatus <> tmp.Status

现在,在数字I中,将“已更改”的值更改为“状态”列