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であっても、すべての月と年を表示するようにしようとしています。

どういうわけか、年と月を列として結合する新しいテーブルを作成しようとしましたが、迷子になりました。

どんな助けでもいただければ幸いです。

4

3 に答える 3

3

を使用している場合は、を使用して目的の結果を得るSQL Server 2005 or aboveことができます。Common Table Expressions (CTE)以下の例は、質問で説明したように結果を取得する方法を示しています。

SQL Fiddleでデモを表示するには、ここをクリックしてください。

説明

  • Createステートメントとinsertステートメントは、テーブルを作成し、いくつかのサンプルデータを入力します。質問で提供されたクエリに基づいてテーブルを作成しました。
  • WITH句内のステートメントは、再帰式を実行しています。この場合、SELECT上記はテーブルdbo.countprojectUNION ALLで利用可能な最小および最大の日付をフェッチします
  • 最小日付がフェッチされると、UNION ALLの後の2番目の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またはRIGHTOUTERJOINを使用する必要があります!

簡単なサンプルは次のとおりです:http ://www.w3schools.com/sql/sql_join_left.asp

あなたは自分でそれを成し遂げるべきです。

ご挨拶

于 2012-04-30T20:14:43.020 に答える
0

残念ながら、SQLステートメントはテーブル内のデータのみを返すことができます。すべての月が必要な場合は、関心のある年/月の組み合わせを含むテーブル、またはできれば、すべての日とそれらに関する情報を含むカレンダーテーブルのいずれかが必要です。

カレンダテーブルの場合、クエリには次のようなfrom句があります。

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 に答える