2012-01-08 2 views
1

У меня есть стол с колонками: MONTH, YEAR, PROJECT_ID, STATUS.Простой запрос SQL-запроса SQL (подсчет изменений значений в столбце)

Статус может быть:

  • 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 = 2011 и month = 8 (к примеру), я понятия не имею, как найти число проектов, которые имели status='C' впервые этот месяц. Есть идеи?

Edit: проекты по-прежнему включены в ряд с status='C' после того, как полный, так что я не могу просто посчитать Cs, как будет возвращать количество проектов, реализованных в этом и предыдущие месяцы (отсюда хронологический порядок и выберите верхнюю часть 1).

Выборочные данные по 10/2010 до 01/2011 месяцев:

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 

^Проекты А и D было завершено в 11/2010. Проект B не изменился до завершения в течение любого из четырех месяцев. Проект C был завершен в 01/2011 году. {Месяц, Год, Проект} - первичный ключ.

Так, входы и выходы будут:

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

Что вы подразумеваете под ** в первый раз в этом месяце ** ??, и почему вы просто не запрашивали: 'select count (*) from tablename, где год = 2011 и месяц = ​​8, а статус = 'C'' –

+0

Должно читать: ... у которого был статус = «C» в первый раз, то есть проект завершен в этом месяце. Ваш запрос дал бы мне количество завершенных проектов, но не количество проектов, которые завершили этот месяц. Проекты включаются в будущие месяцы даже после завершения, причем статус по-прежнему равен «C». Извините, я многое мог бы рассказать! – Chris

+0

Не могли бы вы предоставить образец данных (не обязательно быть реальными данными) и ожидаемый результат? Это сделает ваш вопрос более ясным. – BartekR

ответ

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

Это абсолютно фантастично, большое вам спасибо за вашу помощь. Работает красиво. – Chris

+0

Это не показывает месяцы с некоторой активностью вообще, которые имеют 0 закрытых проектов - возвращают 2 строки вместо запрошенных 4. Если это все, что вы хотите, запрос еще проще: 'select Month = closedon% 100, Year = closedon/100, Count (*) from (выберите Project, closedOn = MIN (Год * 100 + Месяц) из dbo.ProjectStatus где status = 'c' group по проекту) p группа by closedon' – ErikE

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 
+0

Я предлагаю выполнить производные таблицы (distinctMonths и countProjects) самостоятельно, просто чтобы убедиться, что они возвращают ожидаемые результаты. –

+0

Огромное вам спасибо за то, что вы пришли ко всем этим усилиям. Он работает отлично. Я принимаю другое решение, так как это немного проще, но действительно ценю, что вы все это делаете :) – Chris

+0

(требуется небольшое редактирование - countProjects, а не changedProjects в строке 4, а затем требуется GROUP BY distinctMonths.month, distinctMonths.Year в конце) – Chris

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 
1

Мне нравится использовать эту функцию: lead() over(). Если у вас есть, например, это выберите:

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

я нахожу следующее значение в столбце «Статус» с функцией ведущего() и я сравниваю с текущим так:

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 

сейчас, в номере я имею номера измененного значения в столбец «Статус»

Смежные вопросы