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

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

ただいまの
回答率

87.94%

【VB.NET】Accessファイルを読み込んで、.datファイルに出力する

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 812

score 1

前提・実現したいこと

Accessファイルを読み込み、.datファイルに読み込んだデータを出力するプログラムを開発中です。
※AccessファイルはユーザーDSNで接続済み
※コンソールプログラムで開発中

【Accessファイルの構造】
社員ID = 短いテキスト
社員氏名 = 短いテキスト
部門No = 短いテキスト
入社日 = 日付/時刻型
退職日 = 日付/時刻型
出身 = 短いテキスト
部門名 = 短いテキスト
※NULL可のフィールドはありません。

【Accessファイルの中身】※.accdbファイルです。
■社員テーブル
社員ID    社員氏名    部門No    入社日            退職日           出身
00001    田中太郎      001     2000/04/01     2001/04/01      東京
00002    山田太郎      002     2001/04/01     2002/05/01        埼玉
00003    鈴木太郎      003     2002/04/01     2003/06/01        千葉

■部門テーブル
部門No    部門名
001        営業部
002        総務部
003        開発部

【datファイルへの出力イメージ】※ヘッダ・フィールドとの間はタブ区切りで出力
社員ID    社員氏名    部門No    部門名     入社日                  退職日                  勤続年数          出身  
00001    田中太郎      001     営業部   2000年04月      2000年04月01日          1年0ヶ月         東京
00002    山田太郎      002     総務部   2001年04月      2002年05月01日            1年1ヶ月         埼玉
00003    鈴木太郎      003     開発部   2002年04月      2003年06月01日            1年2ヶ月         千葉

ここでは全員退職者という設定でお願いします。

困っていること/分からないこと

① 上記に記載の【datファイルへの出力イメージ】のようなヘッダ・フィールドの順番で出力するための正しい書き方がわからない。
どこに、どのような順番でコードを書けば良いかが分かりません。現在のコードだと任意の位置に出力してくれません。

② 上記に記載の【datファイルへの出力イメージ】のように"勤続年数"を算出する方法が分からない。

③ 上記に記載の【datファイルへの出力イメージ】の〇年〇月や〇年〇月〇日、〇年〇ヶ月というように出力するための書き方が分からない。同じくどこに、どのような方法でコードを書けば良いかが分かりません。

作成中のソースコード

Imports Systen.DataI.Odbc
Imports System.Windows.Forms
Imports System.IO


Module Module1

     Sub Main()

     Dim con As New System.Data.Odbc.OdbcConnection
     Dim command As New System.Data.Odbc.OdbcCommand
     Dim Adapter As New System.Data.Odbc.OdbcDataAdapter(command)
     Dim Syaintable As New DataTable
     Dim Bumontable As New DataTable


     Try

         '接続文字列
         con.ConnectionString = "DSN=sampleDB"

         'DBオープン
         con.Open()

         '列作成(社員テーブル)
         SyainTable.Columns.Add("社員ID", Type.GetType("System.String"))
         SyainTable.Columns.Add("社員氏名", Type.GetType("System.String"))
         SyainTable.Columns.Add("部門No", Type.GetType("System.String"))
         SyainTable.Columns.Add("入社日", Type.GetType("System.DateTime"))
         SyainTable.Columns.Add("退職日", Type.GetType("System.DateTime"))
         SyainTable.Columns.Add("出身", Type.GetType("System.String"))

        '列作成(部門テーブル)
         Bumontable.Colmuns.Add("部門No", Type.GetType("System.String"))
         Bumontable.Colmuns.Add("部門名", Type.GetType("System.String"))

         'DataSetに格納
         Dim ds As New DataSet
         ds.Tables.Add(SyainTable)
         ds.Tables.Add(BumonTable)

         'コマンド
         command = con.CreateCommand

         'SQL
         command.CommandText = "出力イメージになるようなSQLをここに書く"

         Adapter.SelectCommand = command

     'DataTableに格納する
         Adapter.Fill(SyainTable)
         Adapter.Fill(Bumontable)

     'ファイルパス
         Dim FilePath As String
         FilePath = "output.dat"

     '出力するためのファイルを開く処理
         Dim sw As New System.IO.StreamWriter(FilePath, False, System.Text.Encoding.GetEncoding("shift_jis"))

      '変数用意
         Dim colCount As Integer = SyainTable.Columns.Count
         Dim lastColIndex As Integer = colCount -1


        'ヘッダを書き込む
         Dim i As Integer
         For i = 0 To colCount -1

            'ヘッダの取得
            Dim field As String = SyainTable.Columns(i).Caption
            'フィールドを書き込む
            sw.Write(field)

            'タブ区切りで書き込む
            If lastColIndex > i Then
                sw.Write(Tab)
            End If

            Next

            '改行する
            sw.WriteLine()

           'レコードを書き込む
            For Each row In SyainTable.Rows

        Dim strTSV As String
              strTSV = ""
              strTSV = strTSV & row("社員ID").ToString() & Tab
              strTSV = strTSV & row("社員氏名").ToString() & Tab
              strTSV = strTSV & row("部門No").ToString() & Tab
              strTSV = strTSV & row("部門名").ToString() & Tab
              strTSV = strTSV & row("入社日").ToString() & Tab
              strTSV = strTSV & row("退職日").ToString() & Tab
              strTSV = strTSV & row("出身").ToString() 

       '改行する
             sw.WriteLine(strTSV)

            Next

            'sw.Close()

       Catch ex As Exception

            MessageBox.Show(ex.Message, "エラー")

        End Try

        SyainTable.Dispose()
        Adapter.Dispose()
        command.Dispose()
        con.Close()
        con.Dispose()

        MessageBox.Show("処理が終了しました", "通知")


    End Sub

End Module

補足情報(FW/ツールのバージョンなど)

OS:Windows10
開発ツール:Visual Studio2019
フレームワーク:.NET Framework4.8

VBを学び始めてまだ日が浅く、意味のないロジックや無駄なコードがあるかもしれませんが、併せて教えていただければ幸いです。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • SurferOnWww

    2020/04/24 09:45

    上記を質問欄を編集して追記してください。コメント欄での情報提供は好ましくないです。初期画面ではコメント欄は開かないので読まない人がいますから。

    キャンセル

  • SurferOnWww

    2020/04/24 09:50

    聞き忘れました。NULL 可のフィールドはありますか? それはどれですか? これも質問欄を編集して追記してください。

    キャンセル

  • SB_AK

    2020/04/24 09:54

    それぞれ質問欄に反映させました。

    キャンセル

回答 2

checkベストアンサー

+1

Access の「社員テーブル」と「部門テーブル」のデータを別々の DataTable に取得するところまではできていると理解してレスします。(ホントはそれは無駄なような気がしますが、その話はちょっと置いときます)

① 上記に記載の【datファイルへの出力イメージ】のようなヘッダ・フィールドの順番で出力するための正しい書き方がわからない。
どこに、どのような順番でコードを書けば良いかが分かりません。現在のコードだと任意の位置に出力してくれません。

すでに「社員テーブル」と「部門テーブル」の別々の DataTable が取得できているのでそれらを利用するとして・・・ 

まず、【datファイルへの出力イメージ】のもとになるデータを List(Of T) オブジェクト(DataTable ではなく)として取得することにします。その T クラスの定義を追加してください。

DataTableExtensions.AsEnumerable メソッドを使って、それぞれの DataTable から EnumerableRowCollection(Of TRow) オブジェクトを取得し、それらを Linq to Object を使って結合して List(Of T) 型オブジェクトを生成します。

以下のような感じです(あくまで感じ。コードは C# です)。上でいう T クラスが下の画像の Result クラスに該当します(下の例では内部結合の結果 List(Of Result) オブジェクトが取得できています)。質問者さんのケースでは、上で言う T クラスのプロパティは全部 String 型で良いと思います。

イメージ説明

② 上記に記載の【datファイルへの出力イメージ】のように"勤続年数"を算出する方法が分からない。

「入社日」と「退職日」は DataTable では DateTime 型になっていると思います(確認してください)。であれば、上の画像の Select new Result { ... } の ... で "勤続年数" に該当するプロパティに値を代入する際、「入社日」と「退職日」の値を引き算して(結果は TimeSpan 型になるはず)〇年〇ヶ月という文字列に書式設定すれば望む結果が得られるはずです。

③ 上記に記載の【datファイルへの出力イメージ】の〇年〇月や〇年〇月〇日、〇年〇ヶ月というように出力するための書き方が分からない。同じくどこに、どのような方法でコードを書けば良いかが分かりません。

DateTime 型、TimeSpan 型から書式設定をして文字列に変換してください。詳しくは以下の記事を見てください。

カスタム日時形式文字列
https://docs.microsoft.com/ja-jp/dotnet/standard/base-types/custom-date-and-time-format-strings

カスタム TimeSpan 書式指定文字列
https://docs.microsoft.com/ja-jp/dotnet/standard/base-types/custom-timespan-format-strings

以上で【datファイルへの出力イメージ】のもとになる List(Of T) オブジェクトが生成できるはずです。それから質問者さんの言う .dat ファイルは容易に作れるはずです。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/04/24 16:45 編集

    いろいろなことをまとめて聞いてますが、それに対して全体的に自分としては解決に一番最短距離だと思う方法を書いてます。

    > もっとシンプルでもかまいません。

    そうでないと話が通じないなら、質問もシンプルにしないとダメでしょう。DateTime 型を文字列にする際の書式設定の話が聞きたいのなら、それだけに限った質問をするとか。

    > 投稿する前からすでに目を通しています。

    そうであれば、それは最初の質問に自分が知っていることとして書いてください。情報を提供するとそんなことは知っているという人が結構いますが、そういうのは結構カチンと来ますよ。

    キャンセル

  • 2020/04/25 12:05

    質問者さんが無言になってしまいましたが、上の回答の案での実現はギブアップですか? それならそう書いてください。

    せっかく作った 2 つの DataTable は放棄してゼロから考えるのでよければ、たぶん質問者さんにとって一番高い壁であろう Linq to Object を使わないで、ごく基本的なコードで解決する方法もあります。

    もう止めたということならそれでも結構ですので、その旨書いてこのスレッドはクローズしてください。

    とにかく無言は NG です。

    キャンセル

  • 2020/04/26 23:50

    返信遅くなり失礼しました。
    少し別のロジックで再構築してみます。
    ただせっかくここまでアドバイスを頂いたので、今回はSuferさんにBAとします。
    そしてもう少し自分が分かっていないことを分解して、改めて別の質問でアドバイスを頂こうと思います。
    回答ありがとうございました。

    キャンセル

0

① 上記に記載の【datファイルへの出力イメージ】のようなヘッダ・フィールドの順番で出力するための正しい書き方がわからない。
どこに、どのような順番でコードを書けば良いかが分かりません。現在のコードだと任意の位置に出力してくれません。

datてなんじゃ…と思ったらタブ区切りテキストね。

そういうのはCsvHelperみたいなライブラリ使えば良いと思う。

② 上記に記載の【datファイルへの出力イメージ】のように"勤続年数"を算出する方法が分からない。
③ 上記に記載の【datファイルへの出力イメージ】の〇年〇月や〇年〇月〇日、〇年〇ヶ月というように出力するための書き方が分からない。同じくどこに、どのような方法でコードを書けば良いかが分かりません。 

1から10まで説明するようなモノでもないので、方針のみで。

方法は何種類でもあると思うけど、それを導出するためのプロパティを持ったクラスを用意しておき、取得したデータの中身を全部マップしてやれば良いと思われる。

いまの構造を極力そのままやりたいなら、SQLでその計算をしたり文字列のフォーマットまでしておく、という手もあるけど。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/04/24 10:22

    回答ありがとうございます。
    すいません、まだ自分のスキルがそこまで到達していないもので、あまり高度なことはまだできる自信がありません。下手にやろうとすると逆に混乱してしまう恐れがあるので。
    少々べた書きになっても問題ありませんので、もう少し詳細なヒントを教えて頂ければ助かります。

    キャンセル

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

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

関連した質問

同じタグがついた質問を見る