【问题标题】:Simple SQL Server COUNT query (counting changes to values in a column)简单的 SQL Server COUNT 查询(计算列中值的更改)
【发布时间】:2012-02-05 10:24:26
【问题描述】:

我有一个包含列的表: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 已于 11/2010 完成。在所示的四个月中的任何一个月内,项目 B 都没有更改为完成。项目 C 于 01/2011 完成。 {Month,Year,Project} 是主键。

因此,输入和输出将是:

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

【问题讨论】:

  • 你说的那个月第一次是什么意思??你为什么不直接查询:select count(*) from tablename where year = 2011 and month = 8 and status = 'C'
  • 应该阅读:...第一次有 status='C',即项目在那个月完成。您的查询会给我已完成项目的数量,而不是当月完成的项目数量。项目即使在完成后也包括在未来几个月内,状态仍然等于“C”。抱歉,还有很多我本来可以更清楚的!
  • 能否提供一些数据样本(不一定是真实数据)和预期结果?它会让你的问题更清楚
  • 好主意 - 刚刚添加。谢谢!

标签: sql sql-server count


【解决方案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

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

【讨论】:

  • 这真是太棒了,非常感谢您的帮助。效果很好。
  • 这根本不显示有一些活动的月份,有 0 个已关闭的项目——返回 2 行而不是请求的 4 行。如果这就是你想要的,那么查询就更简单了:select Month = closedon % 100, Year = closedon / 100, Count(*) from (select Project, closedOn = MIN(Year*100 + Month) from dbo.ProjectStatus where status = 'c' group by Project) p group by closedon
【解决方案2】:

你来了

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】:
    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
    

    【讨论】:

    • 我建议独立执行派生表(distinctMonths 和 countProjects),只是为了验证它们是否返回了您期望的结果。
    • 非常感谢您付出所有这些努力。它完美地工作。我接受了另一种解决方案,因为它更简单一些,但真的很感谢你付出所有这些努力:)
    • (需要小编辑 - countProjects 而不是 changedProjects 在第 4 行,然后需要 GROUP BY distinctMonths.month,distinctMonths.Year 最后)
    • @Chris 这个格式化 SQL 的学校是怎么称呼的?我经常看到它。聚乙烯醇? (按缩进计划可视化):)
    • @Chris - 为了后代,我已经根据您的建议更新了我的答案
    【解决方案4】:

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

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

    我使用 Lead() 函数找到“状态”列的下一个值,并与当前值进行比较:

    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
    

    现在,在数量上,我将更改值的数量放入“状态”列中

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-07
      • 1970-01-01
      相关资源
      最近更新 更多