2012-04-30 1 views
2

Относительно новый для SQL, и я в тупике по этой маленькой проблеме. Это, кажется, не очень сложно сделать, но я просто не могу понять это.Как получить данные, сгруппированные по месяцам и годам, включая период без данных?

Я пытаюсь получить количество транзакций со стола, но я не могу получить sql, чтобы заставить меня показывать все месяцы, а не только месяцы и год, в которые произошли транзакции.

Вот запрос:

SELECT  YEAR(dbo.countproject.trans_date) AS [TransYear] 
     , MONTH (dbo.countproject.trans_date) AS [TransMonth] 
     , COUNT(Id)       AS TransNum 
FROM  dbo.countproject 
WHERE  dbo.countproject.make_name = 'Honda' 
AND   dbo.countproject.model_name = 'Civic' 
AND   dbo.countproject.type  = 'Sale' 
AND   dbo.countproject.trans_type LIKE '%%EU' 
AND   dbo.countproject.mfr  = '2000' 
GROUP BY YEAR(dbo.countproject.trans_date) 
     , MONTH(dbo.countproject.trans_date) 
ORDER BY YEAR(dbo.countproject.trans_date) 

запрос возвращает следующий результирующий набор:

| TransYear | TransMonth | TransNum | 
|-----------|------------|----------| 
| 2004  |  1  |  5 | 
| 2004  |  3  |  1 | 
| 2005  |  4  |  2 | 

и так далее ....

Я пытаюсь заставить его показать все месяцы и годы, даже если значение NULL.

Я попытался создать новую таблицу, которая будет содержать год и месяц в виде столбцов, чтобы каким-то образом присоединиться к ней, но я проиграл.

Любая помощь будет оценена по достоинству.

+1

Какое поле конкретно обнуляемым? поле 'trans_date' или что-то еще? –

+0

http://stackoverflow.com/questions/1478951/tsql-generate-a-resultset-of-incrementing-dates –

ответ

3

Если вы используете SQL Server 2005 or above, вы могли бы использовать Common Table Expressions (CTE), чтобы получить желаемый результат. Ниже приведен пример того, как вы можете получить результаты, как описано в вопросе.

Click here to view the demo in SQL Fiddle.

Описание:

  • Создание и вставка операторы создают таблицу и заполнит с некоторыми образцами данных. Я создал таблицу на основе запроса, заданного в вопросе.
  • Утверждение в предложении WITH выполняет рекурсивное выражение. В этом случае SELECT выше UNION ALL получают минимальные и максимальные сроки, доступные в таблице dbo.countproject
  • После того, как минимальная дата забирается, то второе ЗЕЬЕСТ после UNION ALL увеличивает срок в 1 месяц с интервалом до момента рекурсивное выражение достигает максимальной даты, доступной в таблице.
  • Рекурсивный CTE предоставил все возможные даты.Этот вывод доступен в таблице с именем alltransactions.
  • Мы должны присоединиться к этому выходу CTE alltransactions с фактическим столом countproject с использованием LEFT OUTER JOIN, так как мы хотим показать все годы и месяцы, даже если транзакций нет.
  • Таблицы alltransactions и countproject соединяются на год и месяц части даты. Затем запрос применяет необходимые фильтры в разделе WHERE, а затем группирует данные по годам и месяцам, прежде чем заказывать его по годам и месяцам.
  • Из данных примера можно указать, что самая ранняя дата в таблице - 2004-07-01, а последняя дата - 2005-12-01. Следовательно, выпуск показывает с 2004 года/месяц 07 по 2005 год/месяц 12.

Надеюсь, что это поможет.

Script:

CREATE TABLE dbo.countproject 
( 
     id   INT   NOT NULL IDENTITY 
    , trans_date DATETIME NOT NULL 
    , make_name VARCHAR(20) NOT NULL 
    , model_name VARCHAR(20) NOT NULL 
    , type  VARCHAR(20) NOT NULL 
    , trans_type VARCHAR(20) NOT NULL 
    , mfr   INT   NOT NULL 
); 

INSERT INTO dbo.countproject (trans_date, make_name, model_name, type, trans_type, mfr) VALUES 
    ('1900-01-01', 'Honda',  'Civic', 'Sale', 'EU', 2000), 
    ('1900-01-01', 'Toyota', 'Corolla', 'Sale', 'EU', 2000), 
    ('2004-07-01', 'Nissan', 'Altima', 'Sale', 'EU', 2000), 
    ('2005-12-01', 'Toyota', 'Camry', 'Sale', 'EU', 2000), 
    ('2004-04-01', 'Ford',  'Focus', 'Sale', 'EU', 2000), 
    ('2005-08-01', 'Honda',  'Civic', 'Sale', 'EU', 2000), 
    ('2005-11-01', 'Toyota', 'Camry', 'Sale', 'EU', 2000), 
    ('2004-08-01', 'Toyota', 'Corolla', 'Sale', 'EU', 2000), 
    ('2005-12-01', 'Honda',  'Civic', 'Sale', 'EU', 2000), 
    ('2004-07-01', 'Honda',  'Civic', 'Sale', 'EU', 2000), 
    ('2004-11-01', 'Honda',  'Civic', 'Sale', 'EU', 2000), 
    ('2005-08-01', 'Honda',  'Civic', 'Sale', 'EU', 2000); 


;WITH alltransactions 
AS 
(
    SELECT  MIN(trans_date) AS continuousdate 
      , MAX(trans_date) AS maximumdate 
    FROM  dbo.countproject 
    WHERE   trans_date <> '1900-01-01' 
    UNION ALL 
    SELECT  DATEADD(MONTH, 1, continuousdate) AS continuousdate 
      , maximumdate 
    FROM  alltransactions 
    WHERE  DATEADD(MONTH, 1, continuousdate) <= maximumdate 
) 
SELECT   YEAR(at.continuousdate)  AS [Year] 
      , MONTH(at.continuousdate) AS [Month] 

      , COUNT(cp.trans_date)  AS [Count] 
FROM   alltransactions at 
LEFT OUTER JOIN countproject cp 
ON    YEAR(at.continuousdate)  = YEAR(cp.trans_date) 
AND    MONTH(at.continuousdate) = MONTH(cp.trans_date) 
AND    cp.make_name    = 'Honda' 
and    cp.model_name    = 'Civic' 
and    cp.type      = 'Sale' 
and    cp.trans_type    LIKE '%EU' 
and    cp.mfr      = '2000' 
GROUP BY  YEAR(at.continuousdate) 
      , MONTH(at.continuousdate) 
ORDER BY  [Year] 
      , [Month]; 

Выход:

Year Month Count 
----- ------ ----- 
2004  4  0 
2004  5  0 
2004  6  0 
2004  7  1 
2004  8  0 
2004  9  0 
2004  10  0 
2004  11  1 
2004  12  0 
2005  1  0 
2005  2  0 
2005  3  0 
2005  4  1 
2005  5  0 
2005  6  0 
2005  7  0 
2005  8  2 
2005  9  0 
2005  10  0 
2005  11  0 
2005  12  1 
+0

Спасибо! Это сделал трюк. Чтобы еще больше усложнить это ... Есть ли в любом случае я могу вырезать 1900-1989 годы из запроса, поскольку у меня есть список из 1356 строк. Я думаю, что в будущем я также хотел бы как-то повернуть таблицу так, чтобы я мог делать все имена как строки и год выпуска в столбцах. Сейчас я собираюсь кое-что прочитать. Еще раз спасибо за вашу помощь! – user1366606

+0

Да, моя ошибка .. Я понял, что использовал неправильное поле в том месте, где оно было близко, чтобы оно не тянуло никаких значений. – user1366606

+0

Он отлично работает. Еще раз спасибо! – user1366606

0

Увы, SQL оператор может возвращать только данные в таблице. Если вы хотите все месяцы, вам нужна таблица с комбинациями год/месяц, в которые вы попадаете, или, желательно, календарную таблицу со всеми днями и информацию о них.

С календарной таблицы, запрос есть из пункта, который выглядел как:

from 
(
    select distinct year(date) as yr, month(date) as mon 
    from calendar c 
    where date between <earliest> and <latest> 
) c 
left outer join CountTable ct 
    on c.yr = year(ct.trans_date) 
    and c.mon = month(ct.trans_date) 
Смежные вопросы