Microsoft Access 掲示板

Excelシートの任意の範囲のみをインポートしたい

11 コメント
views
4 フォロー

レポート出力用のテーブルを作成したいと質問した者ですが、問題を切り分けたいので再投稿致します。

インポートしたいフィールドがB4から始まっています。商品の数は今後増える予定はありません。
1.B列の4行目からI列のB列最終行の範囲のみをインポートし、T_インポートテーブルにあるID、商品1、商品2、商品3、商品4フィールドに書き込みたいです。社名・住所・TELは得意先マスターに入っており、IDでリレーションさせて引っ張ってくるのでT_インポートテーブルには不要です。
2.また、T_インポートテーブルの依頼日フィールドに、B2セルの2023/12/12を入れたいです。

ABCDEFGHI
1
22023/12/12 依頼分
3
4ID社名住所TEL商品1商品2商品3商品4
51
62
My car bomber
作成: 2023/12/11 (月) 22:33:48
最終更新: 2023/12/11 (月) 22:34:02
通報 ...
1
banjo 2023/12/12 (火) 04:51:05 32db9@8d677

横ですが、これは運用を変えられないのでしょうか。
「今欲しがってるもの」→ExcelのピボットテーブルやAccessのクロス集計クエリ→「今あるもの」
なので、「今欲しがってるもの」をベースに変更できないのでしょうか。
メリットとして、商品を柔軟に増やせるなんてのもありますが。

2
My Car Bomber 2023/12/12 (火) 08:41:42 7fdfc@46fae >> 1

初心者なもので仰っていることがあまり理解できず申し訳ありません。
詳しく説明を頂けるとありがたいです!

3
banjo 2023/12/12 (火) 10:18:47 d32ed@4d71e

「初心者なもの」の実際のところがよく分からないので、釈迦に説法だったらすみません。

ExcelやAccessは集計が得意です。しかし、集計後のデータから集計前を復元することは困難または不可能です。
My Car Bomberさんの例であれば、
今あるもの → 今欲しいもの への加工は苦手(機能を自分で作らないといけない)ですが、
今欲しいもの → 今あるもの への加工は得意(機能が用意されている)です。

My Car Bomberさんが例えば
依頼ID 依頼日 取引先ID 商品ID
などと入力するようにすれば、「今あるもの」がすぐに得られるだけでなく、
さまざまな区間(日、月、年他任意の区間)で集計がすぐに得られると思いますが、
切り替える価値がありそうか検討してみて下さい。
(依頼日を Date や CTRL + ; で入力できるし、他でも支援ができます)

4

エクセルの表のフォーマットがデータベースとしては扱いにくい形になってます。
データベース用語とて「正規化」ができていない状態です。
もし、エクセルの表の形式を変更できるならそれを検討してみてはどうでしょう。
banjoさんの回答も同じ意味だと思います。

もし、エクセルの表のフォーマットは変更不可ということなら、
表範囲に名前をつけることはできないでしょうか。
表範囲をテーブルにできないでしょうか。
(テーブルにすれば自動で名前がつきます。)

そうすれば、インポートするときにその名前を指定してインポートできます。

5
My Car Bomber 2023/12/12 (火) 11:01:07 7fdfc@46fae

シートの形式を変更したり、シートを手作業で加工して名前を付けたりすることは出来ないという前提でお願いします。
そのため、任意の範囲のみをインポートする方法を模索しています。

正規化というのは、今回でいえば、A列と1~3行目が無ければ正規化できているということになりますか?

6

エクセルの方は変更できないということであれば、アクセスにインポートしてから、アクセスの方で正規化変換することになります。
Accessではレポートに出力するだけで、出力レイアウトがエクセルの表とほぼ同じということなら必要ないです。
ただ、せっかくアクセスにインポートするならデータベースとして活用したいですよね。
印刷だけなら、エクセルでもできますので。

シートの範囲指定してインポートするなら、TransferSpreadsheet で第6引数でシートや範囲を指定できます。

DoCmd.TransferSpreadsheet acImport, acSpreadsheetTypeExcel9, "テーブル名", "Excelファイル名", False, "シート名$B4:I"

上記はB列からI列の4行目からデータのある最後までインポートします。

7
Function ImportOrderRecords(SourceBookPath As String, SourceSheetName As String)
On Error GoTo Err_ImportOrderRecords

    Const OrderDateCellAddress As String = "B2"
    Const OrderDateSuffix As String = "依頼分"
    Const HeaderRow As Long = 4
    Const KeyColumn As Long = 2
    Const DestinationTableName As String = "T_インポートテーブル"

    ImportOrderRecords = Null

    Dim xlsApp As Object        'Excel.Application
    Dim xlsBook As Object       'Excel.Workbook
    Dim xlsWorksheet As Object  'Excel.Worksheet

    Set xlsApp = CreateObject("Excel.Application")

    Set xlsBook = xlsApp.Workbooks.Open(FileName:=SourceBookPath, ReadOnly:=True)
    Set xlsWorksheet = xlsBook.Worksheets(SourceSheetName)

    Dim varOrderDate As Variant
    Dim lngSuffixPostion As Long

    With xlsWorksheet.Range(OrderDateCellAddress)
        
        varOrderDate = .Value
        lngSuffixPostion = InStrRev(varOrderDate, OrderDateSuffix, -1, vbTextCompare)
        
        If lngSuffixPostion > 0 Then
            varOrderDate = Trim(Left(varOrderDate, lngSuffixPostion - 1))
        End If
        
        If IsDate(varOrderDate) = True Then
            varOrderDate = CDate(varOrderDate)
        Else
            Debug.Print .Address(False, False) & " セルの値: "
            Debug.Print .Value
            MsgBox .Address(False, False) & " セルから依頼日を参照できません。", _
                   vbExclamation, _
                   "ImportOrderRecords"
            Set xlsWorksheet = Nothing
            xlsBook.Close False
            Set xlsBook = Nothing
            xlsApp.Quit
            Set xlsApp = Nothing
            Exit Function
        End If

    End With

    Dim lngFirstDataRow As Long
    Dim lngLastDataRow As Long

    With xlsWorksheet
        
        lngFirstDataRow = HeaderRow + 1
        lngLastDataRow = .Cells(.Rows.Count, KeyColumn).End(xlUp).Row
        
        If lngFirstDataRow > lngLastDataRow Then
            MsgBox "ワークシート[" & .Name & "]からデータ行を参照できません。", _
                   vbExclamation, _
                   "データ参照エラー (ImportOrderRecords)"
            Set xlsWorksheet = Nothing
            xlsBook.Close False
            Set xlsBook = Nothing
            xlsApp.Quit
            Set xlsApp = Nothing
            Exit Function
        End If
        
    End With

    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    Dim strSQL As String

    Set db = CurrentDb

    strSQL = "DELETE * FROM [" & DestinationTableName & "]"
    Debug.Print strSQL
    db.Execute strSQL, dbFailOnError

    strSQL = "SELECT * FROM [" & DestinationTableName & "]"
    Debug.Print strSQL

    Set rs = db.OpenRecordset(strSQL, dbOpenDynaset)

    Dim lngDataRow As Long
    Dim lngInsertCount As Long

    For lngDataRow = lngFirstDataRow To lngLastDataRow
        rs.AddNew
        rs![依頼日].Value = varOrderDate
        With xlsWorksheet.Cells(lngDataRow, KeyColumn)
            rs![社名ID].Value = .Value
            rs![商品名1].Value = .Offset(0, 4).Value
            rs![商品名2].Value = .Offset(0, 5).Value
            rs![商品名3].Value = .Offset(0, 6).Value
            rs![商品名4].Value = .Offset(0, 7).Value
        End With
        rs.Update
        lngInsertCount = lngInsertCount + 1
        Debug.Print lngInsertCount & " 件目のレコードを取り込みました。"
    Next

    ImportOrderRecords = lngInsertCount

Exit_ImportOrderRecords:
On Error Resume Next

    Set rs = Nothing
    Set db = Nothing

    Set xlsWorksheet = Nothing

    If Not xlsBook Is Nothing Then
        xlsBook.Close False
        Set xlsBook = Nothing
    End If

    If Not xlsApp Is Nothing Then
        xlsApp.Quit
        Set xlsApp = Nothing
    End If

    Exit Function

Err_ImportOrderRecords:

    Dim strErrMsg As String

    strErrMsg = Err.Number & ": " & Err.Description

    MsgBox strErrMsg, _
           vbCritical, _
           "実行時エラー (ImportOrderRecords)"

    Resume Exit_ImportOrderRecords
End Function
8
'呼び出し例
Private Sub ImportTest1()

    Dim strTargetFilePath As String
    Dim strTargetSheetName As String
    Dim varRet As Variant

    strTargetFilePath = "C:\FolderName\BookName.xlsx"
    strTargetSheetName = "Sheet1"

    varRet = ImportOrderRecords(strTargetFilePath, _
                                strTargetSheetName)

    If IsNull(varRet) = False Then
        MsgBox strTargetFilePath & " の " & _
               strTargetSheetName & " から " & _
               varRet & " 件のレコードを取り込みました。", _
               vbInformation, _
               "実行完了"
    End If

End Sub
9

1.B列の4行目からI列のB列最終行の範囲のみをインポートし、T_インポートテーブルにあるID、商品1、商品2、商品3、商品4フィールドに書き込みたいです。
2.また、T_インポートテーブルの依頼日フィールドに、B2セルの2023/12/12を入れたいです。

といった処理を実行したいなら以上のようなコードになるでしょう。

ただ、前回のスレッドにおいて

社名ID、社名、住所、TELフィールドを持つ社名マスター
商品ID、商品名フィールドを持つ商品マスターは作成しました

とご説明された通りなのであれば、正規化したテーブルに変換し、互いの[商品ID]同士で[商品マスター]と結合できるようにされた方がよいでしょう。

データ集計を行う上でも「発送用のレポート」を出力する上でも、その方が便利なのは明らかです。

10

補足:

lngLastDataRow = .Cells(.Rows.Count, KeyColumn).End(xlUp).Row

事前バインディングではなく実行時バインディングを採用される場合は、Excel.XlDirection 列挙のメンバー定数 xlUp の代わりに値 -4162 を渡すようにして下さい。

11
My Car Bomber 2023/12/13 (水) 08:32:33 7fdfc@46fae >> 8

大変参考になります、コードの内容理解に私では少し時間がかかりそうですが、読み解いてみます!