C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[5]: SQLで1日毎の集計


(過去ログ 117 を表示中)

[トピック内 8 記事 (1 - 8 表示)]  << 0 >>

■68910 / inTopicNo.1)  SQLで1日毎の集計
  
□投稿者/ ピカチュウ (1回)-(2013/11/25(Mon) 01:34:12)

分類:[データベース全般] 

windows7 oracle

商品   コード 出荷日時
メロン  A1   2013/11/23 09:30:00
イチゴ  A1   2013/11/23 12:10:00 
メロン  A1   2013/11/23 18:15:00
メロン  A1   2013/11/24 03:45:00
イチゴ  A1   2013/11/24 12:40:00
メロン  A2   2013/11/24 22:20:00

商品   コード 2013/11/23 08:30:00〜2013/11/24 08:30:00までのカウント 2013/11/24 08:30:00〜2013/11/25 08:30:00までのカウント  
メロン  A1                 3                           0
イチゴ  A1                 1                           1
メロン  A2                 0                           1
※ 日時の区切りは1日とする(区切りの時間は0時ではなく、ユーザーの時間による、初期は08:30:00)

上記のような集計したいのですが

SELECT 商品, コード, COUNT(*)AS "11/23"
FORM デーブル
WHERE 出荷日時 BETWEEN TO_DATE('2013/11/23 08:30:00','YYYY/MM/DD HH24:MI:SS')AND BETWEEN TO_DATE('2013/11/24 08:30:00','YYYY/MM/DD HH24:MI:SS')
GROUP BY コード, 商品
ORDER BY コード, 商品
--------------------------------------------------------------------

SELECT 商品, コード, COUNT(*)AS "11/24"
FORM デーブル
WHERE 出荷日時 BETWEEN TO_DATE('2013/11/24 08:30:00','YYYY/MM/DD HH24:MI:SS')AND BETWEEN TO_DATE('2013/11/25 08:30:00','YYYY/MM/DD HH24:MI:SS')
GROUP BY コード, 商品
ORDER BY コード, 商品
--------------------------------------------------------------------

    ・
    ・
このSQLだと、これでは毎回日時を入力しなければならないので大変です。(数年分)
初心者の質問ですみません。どうかご教授宜しくお願い致します。
引用返信 編集キー/
■68918 / inTopicNo.2)  Re[1]: SQLで1日毎の集計
□投稿者/ 魔界の仮面弁士 (423回)-(2013/11/25(Mon) 10:31:28)
No68910 (ピカチュウ さん) に返信
> FORM デーブル
FORM (フォーム)ですか?
FROM (フロム) ではなく?

テーブル (table) ではなく、
デーブル なのですか?


> 商品   コード 出荷日時
[コード]というのは、商品コードでも出荷番号でも出荷明細行番号でも無さそうですね。
キー構造が良くわかりませんでしたが、とりあえずそれは無視するとして。


> メロン  A1  3  0
> イチゴ  A1  1  1
> メロン  A2  0  1
> 上記のような集計したいのですが
だとすれば、
  GROUP BY コード, 商品
  ORDER BY コード, 商品 
では駄目ですね。その並びにしたいのであれば、
  GROUP BY コード, 商品
  ORDER BY コード ASC, 商品 DESC
のように、商品側を降順ソートにする必要があります。


もしも、一度の問合せにまとめたいのであれば、下記のようにする手もあります。

SELECT
  商品
, コード
, SUM(CASE WHEN 出荷日時 >= TO_DATE('2013/11/23 08:30:00', 'YYYY/MM/DD HH24:MI:SS')
            AND 出荷日時 <  TO_DATE('2013/11/24 08:30:00', 'YYYY/MM/DD HH24:MI:SS')
  THEN 1 ELSE 0 END) AS "11/23"
, SUM(CASE WHEN 出荷日時 >= TO_DATE('2013/11/24 08:30:00', 'YYYY/MM/DD HH24:MI:SS')
            AND 出荷日時 <  TO_DATE('2013/11/25 08:30:00', 'YYYY/MM/DD HH24:MI:SS')
  THEN 1 ELSE 0 END) AS "11/24"
FROM テーブル名
GROUP BY コード, 商品
ORDER BY コード ASC, 商品 DESC



> このSQLだと、これでは毎回日時を入力しなければならないので大変です。(数年分)
クロス集計ですよね。

データを「列」方向に展開しようとすれば、どうしてもそうなってしまうでしょう。
縦並びで良いのなら、日時指定無しで一括集計することもできますが…。


SELECT
  商品
, コード
, TRUNC( 出荷日時 - INTERVAL '0 8:0:0' DAY TO SECOND, 'DD' ) AS 出荷日
, COUNT(*) AS 出荷数
FROM テーブル名
-- WHERE 出荷日時 BETWEEN TIMESTAMP '2013-11-01 08:00:00.000000000' AND TIMESTAMP '2013-12-01 07:59:59.999999999'
GROUP BY TRUNC( 出荷日時 - INTERVAL '0 8:0:0' DAY TO SECOND, 'DD'), 商品, コード
ORDER BY コード ASC, 商品 DESC



> 初心者の質問ですみません。どうかご教授宜しくお願い致します。
http://dora0.blog115.fc2.com/blog-entry-85.html
http://www.tt.rim.or.jp/~rudyard/torii009.html

引用返信 編集キー/
■68920 / inTopicNo.3)  Re[1]: SQLで1日毎の集計
□投稿者/ shu (427回)-(2013/11/25(Mon) 10:43:30)
No68910 (ピカチュウ さん) に返信

Oracle環境がないのでSQL Serverですが
指定時間分前にずらし日付のみに変換して
その日付で集計してみました。

Select A.コード, A.商品,
     SUM(CASE WHEN 計上日 = '2013/11/23' THEN 1 ELSE 0 END) CNT_11_23,
 SUM(CASE WHEN 計上日 = '2013/11/24' THEN 1 ELSE 0 END) CNT_11_24
FROM
(Select コード, 商品, 出荷日時, Convert(Date,DATEADD(minute,-30,DATEADD(hh,-8,出荷日時))) 計上日
From Table_1) A
GROUP BY A.コード, A.商品
引用返信 編集キー/
■68925 / inTopicNo.4)  Re[2]: SQLで1日毎の集計
□投稿者/ 魔界の仮面弁士 (426回)-(2013/11/25(Mon) 11:44:00)
No68918 (魔界の仮面弁士) に追記
>>このSQLだと、これでは毎回日時を入力しなければならないので大変です。(数年分)
> クロス集計ですよね。
> データを「列」方向に展開しようとすれば、どうしてもそうなってしまうでしょう。

Oracle 11g 以降であれば、PIVOT を使うこともできます。
列を指定するために、IN で日付を列挙する必要があるため、手間は変わりませんが…。


SELECT * FROM (
SELECT 商品, コード, TRUNC( 出荷日時 - INTERVAL '8' HOUR, 'DD' ) AS 出荷日
FROM TBL
)
PIVOT ( COUNT(*) FOR 出荷日 IN ('2013-11-23', '2013-11-24') )
ORDER BY コード, 商品 DESC
引用返信 編集キー/
■68975 / inTopicNo.5)  Re[3]: SQLで1日毎の集計
□投稿者/ ピカチュウ (2回)-(2013/11/26(Tue) 23:44:26)
No68925 (魔界の仮面弁士 さん) に返信

魔界の仮面弁士 さん、ありがとうございます。
内容を少し変えたいことがあります。

 
LIEN  商品    出荷日時(START)
A1  メロン   2013/11/23 09:30:00
A1  メロン   2013/11/23 12:10:00 
A1  イチゴ   2013/11/23 18:15:00
A1  バナナ   2013/11/24 03:45:00
A1  イチゴ   2013/11/24 12:40:00
A2  メロン   2013/11/24 22:20:00

LIEN  2013/11/23 08:30:00〜2013/11/24 08:30:00までのカウント 2013/11/24 08:30:00〜2013/11/25 08:30:00までのカウント  
A1                   3                           1
A2                   0                           1
※ 日時の区切りは1日とする(区切りの時間は0時ではなく、ユーザーの時間による、初期は08:30:00)

LIENグループ化、1日中にいくつかの出荷日時(START)があっても、カウントは1つに数え、商品数を出す(上記の通り)
一度の問い合わせは難しい?なので、下記の通りにやってみました。

SELECT
LIEN, 商品
, CASE WHEN(SUM(CASE WHEN 出荷日時 >= TO_DATE('2013/11/23 08:30:00', 'YYYY/MM/DD HH24:MI:SS')
AND 出荷日時 < TO_DATE('2013/11/24 08:30:00', 'YYYY/MM/DD HH24:MI:SS')
THEN 1 ELSE 0 END)>=1 THEN 1 ELSE 0 END AS "11/23"
, CASE WHEN(SUM(CASE WHEN 出荷日時 >= TO_DATE('2013/11/24 08:30:00', 'YYYY/MM/DD HH24:MI:SS')
AND 出荷日時 < TO_DATE('2013/11/25 08:30:00', 'YYYY/MM/DD HH24:MI:SS')
THEN 1 ELSE 0 END)>=1 THEN 1 ELSE 0 END AS "11/24"
FROM テーブル名
GROUP BY LIEN, 商品
ORDER BY LIEN, 商品

 LIEN  商品  11/23  11/24
  A1 メロン   1    0
  A1 イチゴ   1    0
  A1 バナナ   1    0
  A1 メロン   0    1
  A2 イチゴ   0    1

商品数を集計するために、さらにSUM関数をつけてみました。

〜〜〜〜〜〜
〜〜〜〜〜〜
, SUM(CASE WHEN(SUM(CASE WHEN 出荷日時 >= TO_DATE('2013/11/23 08:30:00', 'YYYY/MM/DD HH24:MI:SS')
AND 出荷日時 < TO_DATE('2013/11/24 08:30:00', 'YYYY/MM/DD HH24:MI:SS')
THEN 1 ELSE 0 END)>=1 THEN 1 ELSE 0 END) AS "11/23"
〜〜〜〜〜〜
〜〜〜〜〜〜

としても単一グループのグループ関数ではありません。とエラーが出てしまいます。
どうしたら上手くいくのでしょうか?
ご教示よろしくお願いします。

※ちなみにORACLE 10Gです
※難しいようでしたらvbaでsqlの結果をだして、エクセルで集計する方法も考えています。



引用返信 編集キー/
■68977 / inTopicNo.6)  Re[4]: SQLで1日毎の集計
□投稿者/ 魔界の仮面弁士 (436回)-(2013/11/27(Wed) 05:31:53)
No68975 (ピカチュウ さん) に返信
> 初期は08:30:00
あ。8時ではなく 8時半でした。
先の私の SQL は、30分ずれていたようで。


> 下記の通りにやってみました。
括弧の数が合わないので、文法エラーになりませんか?

とりあえず、この部分の左括弧が余計で、
> , CASE WHEN(SUM(CASE WHEN 出荷日時
「, CASE WHEN SUM(CASE WHEN 出荷日時」
となるべきではないでしょうか。

もしくは、左括弧を削除する代わりに、右括弧を補完するために
> THEN 1 ELSE 0 END)>=1 THEN
の部分を
「THEN 1 ELSE 0 END))>=1 THEN」
とするか、あるいは
「THEN 1 ELSE 0 END)>=1) THEN」
としてみるとか。


> カウントは1つに数え
23日には、A1・メロンが 2 回出荷されていますが、
それらは 1つとして集計する、ということですね。

⇒11月23日 の A1 は 3 商品(バナナ1回、メロン2回、イチゴ1回)
⇒11月24日 の A1 は 1 商品(イチゴ1回)
⇒11月24日 の A2 は 1 商品(メロン1回)



だとすれば、GROUP BY 句に [商品] を含めずとも、DISTINCT 指定すれば
簡単に抽出できますよ。具体的にいえば、

SELECT
  TRUNC( 出荷日時 - INTERVAL '0 8:30:0' DAY TO SECOND, 'DD' ) AS 出荷日
, LIEN
, COUNT(DISTINCT 商品) AS 出荷数
FROM TBL
GROUP BY TRUNC( 出荷日時 - INTERVAL '0 8:30:0' DAY TO SECOND, 'DD'), LIEN

のようにすることで、

 出荷日     LIEN 出荷数
 ---------- ---- ------
 2013/11/23 A1   3
 2013/11/24 A2   1
 2013/11/24 A2   1

という結果を得ることができるわけです。



クロス集計にしたいのであれば、

SELECT
  LIEN
, COUNT(DISTINCT CASE 
     WHEN 出荷日時 >= TO_DATE('2013/11/23 08:30:00', 'YYYY/MM/DD HH24:MI:SS')
      AND 出荷日時 <  TO_DATE('2013/11/24 08:30:00', 'YYYY/MM/DD HH24:MI:SS')
     THEN 商品 END) AS "11/23"
, COUNT(DISTINCT CASE 
     WHEN 出荷日時 >= TO_DATE('2013/11/24 08:30:00', 'YYYY/MM/DD HH24:MI:SS')
      AND 出荷日時 <  TO_DATE('2013/11/25 08:30:00', 'YYYY/MM/DD HH24:MI:SS')
     THEN 商品 END) AS "11/24"
FROM TBL
GROUP BY LIEN
ORDER BY LIEN

とすることで

 LIEN 11/23 11/24
 ---- ----- -----
 A1       3     1
 A2       0     1

を得られます。



> LIEN  商品    出荷日時(START)
リーエン(lien)という単語には、運送物を留め置く権利、のような意味があるそうですが、
今まで聞いたことが無い言葉だったので、LINE の typo かと思いました…。

引用返信 編集キー/
■68979 / inTopicNo.7)  Re[4]: SQLで1日毎の集計
□投稿者/ shu (430回)-(2013/11/27(Wed) 07:45:25)
No68975 (ピカチュウ さん) に返信

> ※ちなみにORACLE 10Gです
> ※難しいようでしたらvbaでsqlの結果をだして、エクセルで集計する方法も考えています。
>
vbaでの処理が出来るならクロス集計をせず LIEN,商品,出荷日をSelectしてvba側でクロス集計の
形に持っていくのもよいかもしれませんね。
引用返信 編集キー/
■69031 / inTopicNo.8)  Re[5]: SQLで1日毎の集計
□投稿者/ ピカチュウ (3回)-(2013/11/28(Thu) 22:13:54)
No68925 (魔界の仮面弁士 さん) に返信

魔界の仮面弁士さん、shuさんありがとうございます。


理想通りの結果を得ることができました。
SQLについての深い記述はまだまだですので
勉強になりました。


※LIENではなく、LINE(ライン)でした。
FROMもそうでしたし、テーブルもそうでした。
英語が苦手で、時々間違いが出てきます。
またC#も勉強中で、今後も投稿するときに
出てくるかもしれないので、お許しください。


解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -