2

Relatively new to SQL and I am stumped on this little issue. This doesn't seem to be very difficult to do, but I just can't seem to figure it out.

I am trying to get a count of transactions from a table, but I can't seem to get sql to get me to show all of the months instead of only the months and the year that the transactions occured in.

Here is the query:

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)

The query returns the following result set:

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

and so forth....

I am trying to get it to show all the months and years even if the value is NULL.

I tried creating a new table which will have the year and the month as columns to get it to join somehow, but I am lost.

Any help would be appreciated.

4

3 回答 3

3

如果您正在使用SQL Server 2005 or above,则可以使用Common Table Expressions (CTE)来获得所需的结果。下面的示例显示了如何获取问题中描述的结果。

单击此处查看 SQL Fiddle 中的演示。

说明

  • 创建和插入语句创建表并填充一些示例数据。我根据问题中提供的查询创建了表。
  • WITH 子句中的语句正在执行递归表达式。在这种情况下,SELECT上述获取表dbo.countprojectUNION ALL中可用的最小和最大日期
  • 获取最小日期后,UNION ALL 之后的第二个 SELECT 语句以 1 个月的间隔递增日期,直到递归表达式达到表中可用的最大日期。
  • 递归 CTE 已生成所有可能的可用日期。此输出在名为alltransactions的表中可用。
  • 我们必须将此 CTE 输出与使用alltransactions的实际表连接起来,因为即使没有交易,我们也希望显示所有年份和月份。countprojectLEFT OUTER JOIN
  • 表格alltransactions和在日期countproject年份月份部分连接。然后,查询在WHERE子句中应用必要的过滤器,然后按年和月对数据进行分组,然后按年和月对其进行排序。
  • 从样本数据中可以看出,表中最早的日期是2004-07-01,最晚的日期是2005-12-01。因此,输出显示从 2004 年 / 月 07 到 2005 年 / 月 12。

希望有帮助。

脚本

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
于 2012-04-30T21:15:58.233 回答
0

您必须使用 LEFT 或 RIGHT OUTER JOIN!

这是一个简单的示例:http ://www.w3schools.com/sql/sql_join_left.asp

你应该自己完成它。

问候

于 2012-04-30T20:14:43.020 回答
0

Alas, the SQL statement can only return the data in the table. If you want all months, you need either a table with the year/month combinations you are intererested in or, preferably, a calendar table with all days and information about them.

With a calendar table, your query have a from clause that looked like:

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)
于 2012-04-30T20:14:53.967 回答