質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.20%

日付でグループ化されたクエリを、さらに項目別にグループ化したい

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,281

sheephuman

score 48

質問の内容がこれであっているのかどうか疑わしいのですが。
以下のようなCSVデータを使うものとします。

1459,食費,8月6日,さば、豚切り落とし他
970,食費,8月9日,とまと、枝豆
86,娯楽,8月14日,マンガレンタル
324,雑貨,8月14日,ボタン電池、漬物  100円ショップ
172,娯楽,8月14日,中古マンガ
216,食費,8月14日,炭酸水
705,食費,8月14日,
669,食費,8月8日,
172,娯楽,8月8日,マンガレンタル
206,食費,8月8日,
268,食費,8月8日,コンビニ

コードはoledbを使い、以下のようになります。

System.Data.OleDb 名前空間

ソースコードを実行可能なものに書き直します。失礼しました。
それと、プロジェクトファイルを添付しておきます。

https://box.yahoo.co.jp/guest/viewer?sid=box-l-jjsgnkx53gwi3lt2r7nmvpbfvm-1001&uniqid=71f9a0e5-71d4-426e-97d7-215d6b9c3997&viewtype=detail

  using System;
using System.Data.OleDb;
using System.Data;
using System.IO;
using System.Windows.Forms;


namespace WindowsFormsApp4
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

         CSV_to_chart("2018年8月.csv");
        }

        private void CSV_to_chart(string ReadFile)
        {



            chart1.Series.Clear();
            chart1.Series.Add("合計");







            try
            {
                string current = Directory.GetCurrentDirectory();

                // Full path to the data source file

                string file = ReadFile;
                string path = current + "\\Data\\";
             //実行ファイル直下に「Data」ファルダを作る         

                // Create a connection string.
                string ConStr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" +
                path + ";Extended Properties=\"Text;HDR=No;FMT=Delimited\"";
                OleDbConnection myConnection = new OleDbConnection(ConStr);



                string mySelectQuery = "";



                mySelectQuery = "SELECT F3, F2, Sum(F1) FROM " + "\\" + "[" + file + "]" + " Group by f3, f2 Order by Format(F3,'MMDD'), F2";
                //+、-スペース入りファイル名も使えるようにする



                chart1.Series[0].Label = "#VAL{C}";
                //Chartに価格ラベルを表示する



                OleDbCommand myCommand = new OleDbCommand(mySelectQuery, myConnection);
                // Open the connection and create the reader
                myCommand.Connection.Open();
                OleDbDataReader myReader = myCommand.ExecuteReader(CommandBehavior.CloseConnection);


                chart1.ChartAreas[0].InnerPlotPosition.Width = 90;
                chart1.ChartAreas[0].InnerPlotPosition.Height = 90;
                chart1.ChartAreas[0].InnerPlotPosition.X = 8;
                chart1.ChartAreas[0].InnerPlotPosition.Y = 0;


                chart1.ChartAreas[0].IsSameFontSizeForAllAxes = true;


                chart1.Series[0].Points.DataBindXY(myReader, "0", myReader, "1");

                myReader.Close();
                myConnection.Close();


            }
            catch (OleDbException OleEx)
            { //Console.WriteLine(OleEx.ToString());

                MessageBox.Show(OleEx.Message);
            }
        }
    }
}

表示は以下のようになります。
以上をこのように日付でグループ化しています。

イメージ説明

また、クエリを変えることで、項目毎に集計も出来ました。

mySelectQuery = "SELECT F2,Sum(F1) FROM " + "\\" + "[" + file + "]" + " Group by F2";

イメージ説明

今のところここまでが限界で、
日時
┗項目
 
のように集計出来るのが理想なんです。    
サブクエリというのがあると知り、打ち込んでみましたが、例外を吐くばかりで上手くいきません。

適切なクエリの書き方を教えていただけると助かります。   

 念のために
  イメージ説明
    このように表示させるようなクエリがあれば書きたいということです。

回答いただいたコードの結果
mySelectQuery = "SELECT F3, F2, Sum(F1) FROM " + "\\" +"[" + file+"]" + " Group by f3, f2 Order by Format(F3,'MMDD'), F2";
  
イメージ説明

ちなみに 自分が試したのは

 mySelectQuery = "SELECT F3, F2, Sum(F1) FROM " + "\\" +"[" + file+"]" + " Group by f3, f2 Order by Format(F3,'MMDD')"でした。

他のもの
//mySelectQuery = "SELECT *,Sum(F1) FROM " + "\\" + file + " WHERE F2 = (SELECT F2 FROM " + "\\" + file + ")";

 
意味がよくわかってないと思います。

  1. さらに試したこと
    Quitaの記事からの流用になります。
    【C#】CSV、Excelファイルの内容をDataTableに格納する  
public static DataTable GetDataTableFromCSV(String strFilePath, Boolean isInHeader = true)
        {
            dt = new DataTable();


            String strInHeader = isInHeader ? "YES" : "NO";                // ヘッダー設定
            String strCon = "Provider=Microsoft.ACE.OLEDB.12.0;"      // プロバイダ設定
                                                                      //= "Provider=Microsoft.Jet.OLEDB.4.0;"     // Jetでやる場合
                                + "Data Source=" + Path.GetDirectoryName(strFilePath) + "\\; "          // ソースファイル指定
                                + "Extended Properties=\"Text;HDR=" + strInHeader + ";FMT=Delimited\"";
            OleDbConnection con = new OleDbConnection(strCon);
            String strCmd = "SELECT * FROM [" + Path.GetFileName(strFilePath) + "]";

            // 読み込み
            OleDbCommand cmd = new OleDbCommand(strCmd, con);
            OleDbDataAdapter adp = new OleDbDataAdapter(cmd);
            adp.Fill(dt);
            //  ds.Tables.Add(dt);

            return dt;
        }

さらに

      private void CSV_to_chart(string ReadFile)
        {

            dt = GetDataTableFromCSV(current + "\\2018年8月.csv", false);




        string[] seriesArray = dt.AsEnumerable().Select(r => r.Field<string>("F2")).Distinct().ToArray();
                //"F2"を名前解決する処理

        foreach (string s in seriesArray)
         {
           chart1.Series.Add(s);
         }


        mySelectQuery = "SELECT F3, F2, Sum(F1) FROM " + "\\" + "[" + file + "]" + " Group by f3, f2 Order by Format(F3,'MMDD'), F2";
         //グラフが表示されない
     

 // 以下略

このようにすることで以下の結果を得ました。
イメージ説明

系列が追加されていないので表示されないのかと思ったんですが、クエリ側との不一致があるのかやはり表示されませんでした。

参考までに自作の記事を添えておきます。
C# DataTable to Chart Display(家計簿用サンプル) 

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • SurferOnWww

    2018/08/15 12:08

    > (1) Chart に渡すためのデータの作り方 の方です。 ← 質問者さんのやりたいことを実現するには、PIVOT 関係演算子を利用して元データからクロス集計表を生成といった操作が必要になりそうですが、CSV + ADO.NET + JET では無理なような気がします。SQL Server は使えないのですか?

    キャンセル

  • SurferOnWww

    2018/08/15 12:30

    ちなみに、PIVOT 関係演算子を利用してクロス集計の例はこのようなことです → http://surferonwww.info/BlogEngine/post/2010/08/07/Use-of-PIVOT.aspx この記事の Employee を質問者さんのデータの費目で考えると分かりやすいのではないかと思います。

    キャンセル

  • SurferOnWww

    2018/08/15 20:10

    PIVOT 関係演算子を利用してクロス集計と書きましたが SUM 句を使ってできるかもしれません。ただし、CSV + ADO.NET + JET で可能かどうかは分かりませんが。SQL Server を使った場合の例を回答欄に書いておきます。

    キャンセル

回答 3

checkベストアンサー

+1

質問へのコメント欄に、Chart のサンプルの紹介を回答欄に紹介しておきますと書きましたが、それを以下に書きます。

以下のページから Windows Forms アプリ用と ASP.NET Web Forms アプリ用のサンプルの両方をダウンロードできます。

Samples Environments for Microsoft Chart Controls
https://code.msdn.microsoft.com/mschart

Windows Forms 用のサンプルは上のページで[C# (5.6MB)]をクリックしてダウンロードしてください。完全な C# の Windows Forms アプリのソリューションが zip されています。

それを適当なフォルダに解凍して Visual Studio(.NET4 なので 2010 以降のバージョン)で開いて実行すれば、基本の解説、いろいろなタイプのサンプルのデモ、それを作るための C# および VB.NET サンプルコード等が満載のアプリが動くはずです。

解説が英語であるのを厭わなければこのサンプルは今後の開発に非常に有益なものになると思います。

このスレッドの質問者さんの問題がサンプルを見ると解決するかどうかは分かりませんが、解決のためのヒントはあるかもしれません。

解決できなくとも、今後の開発に役立つはずですので、ダウンロードして設定する手間をかけても損はないと思います。

一点だけ、以下の記事に書いた通りフォルダ名の問題があって変更が必要と思いますので注意してください。

Chart Samples
http://surferonwww.info/BlogEngine/post/2016/02/14/chart-samples.aspx

【追記】

質問に対する私のコメントで、

PIVOT 関係演算子を利用してクロス集計と書きましたが SUM 句を使ってできるかもしれません。ただし、CSV + ADO.NET + JET で可能かどうかは分かりませんが。SQL Server を使った場合の例を回答欄に書いておきます。

と書きましたが、それを以下に書いておきます。

以下の記事は積み上げ棒グラフ (SeriesChartType.StackedColumn) ですが、それを普通の棒グラフ (SeriesChartType.Column) にしたものが質問者さんが望む形のものになると思います。

[ASP.NET]チャート・コントロールで積み上げ棒グラフを作成するには?[3.5、C#、VB]
http://www.atmarkit.co.jp/fdotnet/dotnettips/1004aspchartstack/aspchartstack.html

以下のコードで望む形になると思います。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.Windows.Forms.DataVisualization.Charting;

namespace WindowsFormsChart
{
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }

        private DataTable CreateDataTable()
        {
            string connString = 
                @"Data Source=(local)\sqlexpress;Initial Catalog=Database;Integrated Security=True";
            string selectQuery =
                @"SELECT 
                    Month, 
                    SUM(CASE WHEN Name = N'三吉' THEN Sales ELSE 0 END) AS 三吉, 
                    SUM(CASE WHEN Name = N'春日' THEN Sales ELSE 0 END) AS 春日, 
                    SUM(CASE WHEN Name = N'東雲' THEN Sales ELSE 0 END) AS 東雲, 
                    SUM(CASE WHEN Name = N'府中' THEN Sales ELSE 0 END) AS 府中, 
                    SUM(CASE WHEN Name = N'広島' THEN Sales ELSE 0 END) AS 広島 
                    FROM Shop GROUP BY Month";

            using (SqlConnection connection = new SqlConnection(connString))
            {
                SqlDataAdapter adapter = new SqlDataAdapter();
                adapter.SelectCommand = new SqlCommand(selectQuery, connection);
                DataTable table = new DataTable();
                adapter.Fill(table);
                return table;
            }
        }

        private void Form2_Load(object sender, EventArgs e)
        {
            Chart chart = new Chart()
            {
                Name = "chart1",
                Width = 600,
                DataSource = CreateDataTable()
            };

            this.Controls.Add(chart);

            Legend legend = new Legend()
            {
                DockedToChartArea = "ChartArea1",
                IsDockedInsideChartArea = false,
                Name = "Legend1"
            };
            chart.Legends.Add(legend);

            Series series = new Series()
            {
                Name = "三吉",
                ChartType = SeriesChartType.Column,
                Legend = "Legend1",
                XValueMember = "Month",
                YValueMembers = "三吉"
            };
            chart.Series.Add(series);

            series = new Series()
            {
                Name = "春日",
                ChartType = SeriesChartType.Column,
                Legend = "Legend1",
                XValueMember = "Month",
                YValueMembers = "春日"
            };
            chart.Series.Add(series);

            series = new Series()
            {
                Name = "東雲",
                ChartType = SeriesChartType.Column,
                Legend = "Legend1",
                XValueMember = "Month",
                YValueMembers = "東雲"
            };
            chart.Series.Add(series);

            series = new Series()
            {
                Name = "府中",
                ChartType = SeriesChartType.Column,
                Legend = "Legend1",
                XValueMember = "Month",
                YValueMembers = "府中"
            };
            chart.Series.Add(series);

            series = new Series()
            {
                Name = "広島",
                ChartType = SeriesChartType.Column,
                Legend = "Legend1",
                XValueMember = "Month",
                YValueMembers = "広島"
            };
            chart.Series.Add(series);

            ChartArea chartArea = new ChartArea()
            {
                Name = "ChartArea1",
                AxisY = new Axis() { Title = "売上高" },
                AxisX = new Axis() { Title = "売上月" }
            };
            chart.ChartAreas.Add(chartArea);
        }
    }
}

イメージ説明

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/08/15 11:13

    ありがとうございます。このサンプルの存在は知っていましたが、量も多く複雑に思われ、それほど査読しておりませんでした。
    この機会にじっくり読んでみようと思います。

    キャンセル

  • 2018/08/15 21:16

    なるほど。試してみようと思います。
    そろそろ閉め切ろうかと思った矢先の回答、ありがとうございました。
    感謝します。

    キャンセル

+1

このようなクエリでは要件は満たされますか?

SELECT F3, F2, Sum(F1) FROM " + "\\" +"[" + file+"]" + " Group by f3, f2 Order by Format(F3,'MMDD'), F2

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/08/14 18:35

    実はそれを真っ先に試しました。忘れてました。
    例外は出ないものの、グラフが出力されないという結果になりました。

    キャンセル

  • 2018/08/14 18:49

    私見なのですが、MicroSoftのChartはどのサンプルでも複数系列を表示させる場合、DataBindするか、for文で回して一つずつSeriesをAddする形になるようです。 クエリが正しくても、Chart側で出力できない仕様なのではと思いました。

    キャンセル

-1

[Chart][Tips] コードから棒グラフを作成する

質問の画像がここからみつかりました。
質問を編集して画像の入手先を明らかにし、このページを参考に作ってください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/08/15 11:51

    返事がない。ただの○○のようだ。

    キャンセル

  • 2018/08/15 21:14

    URLは載せていませんが、もちろん知っております。
    この例ではデータバインディングを使用しており、SUM句で集計といった処理が入る余地がないように思われました。
    この作例で集計する方法をご存知でしたら回答をお待ちしております。

    キャンセル

  • 2018/08/15 21:19

    知っておりますとかじゃなく、画像借りたなら出典示さないとダメでしょ。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.20%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる