5

月次ステータス データベース ビューに基づいてレポートを作成する必要があります。ビュー内のデータは次のようになります。

Category | Revenue  |  Yearh  |  Month
Bikes      10 000      2008        1
Bikes      12 000      2008        2
Bikes      12 000      2008        3
Bikes      15 000      2008        1
Bikes      11 000      2007        2
Bikes      11 500      2007        3
Bikes      15 400      2007        4


...など

ビューには、製品カテゴリ、収益、年、および月があります。2007 年と 2008 年を比較して、売上のない月を 0 と表示するレポートを作成したいと考えています。したがって、レポートは次のようになります。

Category  |  Month  |  Rev. This Year  |  Rev. Last Year
Bikes          1          10 000               0
Bikes          2          12 000               11 000
Bikes          3          12 000               11 500
Bikes          4          0                    15 400


注目すべき重要な点は、月 1 は 2008 年にのみ売上があり、したがって 2007 の場合は 0 であるということです。また、月 4 は 2008 年にのみ売上がないため、0 ですが、2007 年に売上があり、まだ表示されています。

また、このレポートは実際には会計年度のものです。そのため、2007 年または 2008 年のいずれかの月 5 に売上がなかった場合、両方に 0 の空の列があるとよいでしょう。

私が得たクエリは次のようになります。

SELECT 
    SP1.Program,
    SP1.Year,
    SP1.Month,
    SP1.TotalRevenue,
    IsNull(SP2.TotalRevenue, 0) AS LastYearTotalRevenue

FROM PVMonthlyStatusReport AS SP1 
     LEFT OUTER JOIN PVMonthlyStatusReport AS SP2 ON 
                SP1.Program = SP2.Program AND 
                SP2.Year = SP1.Year - 1 AND 
                SP1.Month = SP2.Month
WHERE 
    SP1.Program = 'Bikes' AND
    SP1.Category = @Category AND 
    (SP1.Year >= @FinancialYear AND SP1.Year <= @FinancialYear + 1) AND
    ((SP1.Year = @FinancialYear AND SP1.Month > 6) OR 
     (SP1.Year = @FinancialYear + 1 AND SP1.Month <= 6))

ORDER BY SP1.Year, SP1.Month

このクエリの問題は、2008 年には売上がありませんでしたが、2007 年には実際に売上があったため、上記のサンプル データの 4 行目を返さないことです。

これはおそらく一般的なクエリ/問題ですが、長い間フロントエンド開発を行った後、私の SQL は錆びています。どんな助けでも大歓迎です!

ところで、私はこのクエリに SQL 2005 を使用しているので、役立つ新機能があれば教えてください。

4

6 に答える 6

5

Case ステートメントは、SQL の親友です。また、両方の月で 0 回転を生成するための時間の表も必要です。

仮定は、次の表の可用性に基づいています。

販売: カテゴリ | 収益 | 年 | 年 | 月

tm: 年 | 月 (レポートに必要なすべての日付が入力されています)

空の行のない例 1:

select
    Category
    ,month
    ,SUM(CASE WHEN YEAR = 2008 THEN Revenue ELSE 0 END) this_year
    ,SUM(CASE WHEN YEAR = 2007 THEN Revenue ELSE 0 END) last_year

from
    sales

where
    year in (2008,2007)

group by
    Category
    ,month

戻り値:

Category  |  Month  |  Rev. This Year  |  Rev. Last Year
Bikes          1          10 000               0
Bikes          2          12 000               11 000
Bikes          3          12 000               11 500
Bikes          4          0                    15 400

空の行を含む例 2: サブクエリを使用します (他のクエリは使用しない場合もあります)。製品と年月の組み合わせごとに空の行が返されます。

select
    fill.Category
    ,fill.month
    ,SUM(CASE WHEN YEAR = 2008 THEN Revenue ELSE 0 END) this_year
    ,SUM(CASE WHEN YEAR = 2007 THEN Revenue ELSE 0 END) last_year

from
    sales
    Right join (select distinct  --try out left, right and cross joins to test results.
                   product
                   ,year
                   ,month
               from
                  sales --this ideally would be from a products table
                  cross join tm
               where
                    year in (2008,2007)) fill


where
    fill.year in (2008,2007)

group by
    fill.Category
    ,fill.month

戻り値:

Category  |  Month  |  Rev. This Year  |  Rev. Last Year
Bikes          1          10 000               0
Bikes          2          12 000               11 000
Bikes          3          12 000               11 500
Bikes          4          0                    15 400
Bikes          5          0                    0
Bikes          6          0                    0
Bikes          7          0                    0
Bikes          8          0                    0

ほとんどのレポート ツールがこのクロス集計またはマトリックス機能を実行することに注意してください。SQL Server 2005 には、これを実行するピボット構文もあると思います。

追加のリソースを次に示します。CASE http://www.4guysfromrolla.com/webtech/102704-1.shtml SQL Server 2005 PIVOT http://msdn.microsoft.com/en-us/library/ms177410.aspx

于 2008-08-20T01:28:08.567 に答える
4

@Christian -- マークダウン エディタ -- UGH; 特に、投稿のプレビューと最終バージョンが一致しない場合... @Christian -- 完全外部結合 -- 完全外部結合は、WHERE 句に SP1 への参照があり、WHERE 句が適用されているという事実によって却下されます。 JOINの後。テーブルの 1 つをフィ​​ルタリングして完全な外部結合を行うには、WHERE 句をサブクエリに入れる必要があるため、結合のにフィルタリングが行われるか、すべての WHERE 基準を JOIN ON 句に構築しようとします。めちゃくちゃ醜い。まあ、実際にはこれを行うためのきれいな方法はありません。

@ジョナス:これを考慮して:

また、このレポートは実際には会計年度のものです。そのため、2007 年または 2008 年のいずれかの月 5 に売上がなかった場合、両方に 0 の空の列を作成したいと考えています。

そして、この仕事はきれいなクエリでは実行できないという事実から、私は間違いなくあなたが実際に望む結果を得ようとします. 醜いクエリを使用したり、実際に必要な正確なデータを取得することさえできなくても意味がありません。;)

したがって、これを 5 つの手順で行うことをお勧めします。
1. 結果を一致させたい形式で一時テーブルを作成します
。 2. 月の列に 1 ~ 12 を含む 12 行を入力します
。 SP1 ロジックを使用して " 列
4. SP2 ロジックを使用して "昨年" 列を更新します
5. 一時テーブルから選択します

もちろん、これを達成するためのストアド プロシージャを作成できるという仮定に基づいて作業していると思います。技術的には、このバッチ全体をインラインで実行できるかもしれませんが、そのような醜さはめったに見られません。SP を作成できない場合は、サブクエリを介して完全外部結合にフォールバックすることをお勧めしますが、どちらの年も売上がなかった月には行が得られません。

于 2008-08-20T00:39:00.743 に答える
2

トリックは、ISNULL を使用して FULL JOIN を実行し、いずれかのテーブルから結合された列を取得することです。通常、これをビューまたは派生テーブルにラップします。それ以外の場合は、WHERE 句でも ISNULL を使用する必要があります。

SELECT 
    Program,
    Month,
    ThisYearTotalRevenue,
    PriorYearTotalRevenue
FROM (
    SELECT 
        ISNULL(ThisYear.Program, PriorYear.Program) as Program,
        ISNULL(ThisYear.Month, PriorYear.Month),
        ISNULL(ThisYear.TotalRevenue, 0) as ThisYearTotalRevenue,
        ISNULL(PriorYear.TotalRevenue, 0) as PriorYearTotalRevenue
    FROM (
        SELECT Program, Month, SUM(TotalRevenue) as TotalRevenue 
        FROM PVMonthlyStatusReport 
        WHERE Year = @FinancialYear 
        GROUP BY Program, Month
    ) as ThisYear 
    FULL OUTER JOIN (
        SELECT Program, Month, SUM(TotalRevenue) as TotalRevenue 
        FROM PVMonthlyStatusReport 
        WHERE Year = (@FinancialYear - 1) 
        GROUP BY Program, Month
    ) as PriorYear ON
        ThisYear.Program = PriorYear.Program
        AND ThisYear.Month = PriorYear.Month
) as Revenue
WHERE 
    Program = 'Bikes'
ORDER BY 
    Month

これで、最小要件 (2007 年または 2008 年、あるいはその両方の売上を含む行) が得られるはずです。どちらの年も売上のない行を取得するには、1 ~ 12 の数値テーブルに INNER JOIN するだけです (それらの 1 つを持っていますよね?)。

于 2008-08-25T02:57:03.663 に答える
1

私は間違っているかもしれませんが、左結合だけでなく完全な外部結合を使用するべきではありませんか? そうすれば、両方のテーブルから「空の」列を取得できます。

http://en.wikipedia.org/wiki/Join_(SQL)#Full_outer_join

于 2008-08-19T23:32:00.813 に答える
1

マークダウンについて - ええ、それはイライラします。エディターは私の HTML テーブルをプレビューしましたが、投稿後に消えてしまいました。そのため、投稿からすべての HTML フォーマットを削除する必要がありました...

@kcrumley同様の結論に達したと思います。このクエリは簡単に見苦しくなります。私はあなたの答えを読む前に、同様の(しかし異なるアプローチ)を使用して実際にこれを解決しました。レポート データベースでストアド プロシージャと関数を作成するためのアクセス権があります。製品カテゴリと会計年度をパラメーターとして受け入れるテーブル値関数を作成しました。これに基づいて、関数は 12 行を含むテーブルに入力します。利用可能な販売がある場合、行にはビューからのデータが取り込まれます。そうでない場合、行の値は 0 になります。

次に、関数から返された 2 つのテーブルを結合します。すべてのテーブルに 12 個のローブがあることがわかっているので、割り当ては簡単です。製品カテゴリと月に参加できます。

SELECT 
    SP1.Program,
    SP1.Year,
    SP1.Month,
    SP1.TotalRevenue AS ThisYearRevenue,
    SP2.TotalRevenue AS LastYearRevenue
FROM GetFinancialYear(@Category, 'First Look',  2008) AS SP1 
     RIGHT JOIN GetFinancialYear(@Category, 'First Look',  2007) AS SP2 ON 
         SP1.Program = SP2.Program AND 
         SP1.Month = SP2.Month

GetFinancialYear 関数は非常に面倒なので、あなたのアプローチはおそらく少しきれいだと思います! しかし、少なくともそれは機能します - 今のところ私を幸せにします ;)

于 2008-08-20T01:09:30.110 に答える