0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【VBA】AWS GlueのDecimal型をDouble型に一括変換するツールを作った

Last updated at Posted at 2026-01-06

はじめに

AWS Glueでデータパイプラインを構築していると、Decimal型の扱いに悩むことがあります。

特に以下のようなケースでDecimal型からDouble型への変換が必要になることがあります。

  • Athenaでのクエリパフォーマンス改善
  • 下流システムがDouble型のみ対応
  • 精度よりも処理速度を優先したい場合
  • レガシーシステムとの連携

手作業で置換するのは面倒ですし、見落としも発生しがちです。そこで、PySpark / Scala / JSONスキーマファイルを一括変換するVBAツールを作成しました。

対応する変換パターン

本ツールは、AWS Glueで使われる様々な型定義パターンに対応しています。

PySpark(Python)

# 変換前
from pyspark.sql.types import DecimalType

schema = StructType([
    StructField("price", DecimalType(10, 2)),
    StructField("quantity", DecimalType()),
])

df = df.withColumn("amount", col("amount").cast("decimal(18,4)"))
# 変換後
from pyspark.sql.types import DoubleType  # ※importの追加は手動で確認

schema = StructType([
    StructField("price", DoubleType()),
    StructField("quantity", DoubleType()),
])

df = df.withColumn("amount", col("amount").cast("double"))

Scala

// 変換前
import org.apache.spark.sql.types.{DataTypes, DecimalType}

val schema = StructType(Seq(
  StructField("price", DataTypes.createDecimalType(10, 2)),
  StructField("rate", Decimal(18, 6))
))
// 変換後
import org.apache.spark.sql.types.{DataTypes, DoubleType}

val schema = StructType(Seq(
  StructField("price", DataTypes.DoubleType),
  StructField("rate", Double)
))

AWS Glue JSONスキーマ

// 変換前
{
  "columns": [
    {"name": "price", "type": "decimal(10,2)"},
    {"name": "rate", "type": "decimal"}
  ]
}
// 変換後
{
  "columns": [
    {"name": "price", "type": "double"},
    {"name": "rate", "type": "double"}
  ]
}

機能一覧

マクロ名 機能 用途
ConvertDecimalToDouble_Folder フォルダ一括変換 複数ファイルをまとめて変換
ConvertDecimalToDouble_SingleFile 単一ファイル変換 特定ファイルのみ変換
PreviewConversion プレビュー 変換結果を事前確認
ConvertWithCustomPatterns カスタムパターン 独自の変換ルールを追加

ソースコード

'==============================================================================
' AWS Glue Decimal to Double Converter
' 概要: AWS Glueのソースコード内のDecimal型をDouble型に一括変換するVBAマクロ
'==============================================================================
Option Explicit

'------------------------------------------------------------------------------
' メイン処理: フォルダ内の全ファイルを変換
'------------------------------------------------------------------------------
Public Sub ConvertDecimalToDouble_Folder()
    Dim folderPath As String
    Dim outputFolder As String
    Dim fso As Object
    Dim folder As Object
    Dim file As Object
    Dim convertedCount As Long
    Dim totalFiles As Long
    
    ' フォルダ選択ダイアログ
    With Application.FileDialog(msoFileDialogFolderPicker)
        .Title = "変換対象のフォルダを選択してください"
        If .Show = -1 Then
            folderPath = .SelectedItems(1)
        Else
            MsgBox "キャンセルされました。", vbInformation
            Exit Sub
        End If
    End With
    
    ' 出力フォルダの作成
    outputFolder = folderPath & "\converted_" & Format(Now, "yyyymmdd_hhnnss")
    
    Set fso = CreateObject("Scripting.FileSystemObject")
    If Not fso.FolderExists(outputFolder) Then
        fso.CreateFolder outputFolder
    End If
    
    ' 対象拡張子
    Dim targetExtensions As Variant
    targetExtensions = Array(".py", ".scala", ".json", ".txt")
    
    Set folder = fso.GetFolder(folderPath)
    
    ' ファイル処理
    For Each file In folder.Files
        If IsTargetFile(file.Name, targetExtensions) Then
            totalFiles = totalFiles + 1
            If ConvertFile(file.Path, outputFolder & "\" & file.Name) Then
                convertedCount = convertedCount + 1
            End If
        End If
    Next file
    
    ' 結果表示
    MsgBox "変換完了!" & vbCrLf & _
           "対象ファイル数: " & totalFiles & vbCrLf & _
           "変換成功: " & convertedCount & vbCrLf & _
           "出力先: " & outputFolder, vbInformation
    
    Set fso = Nothing
End Sub

'------------------------------------------------------------------------------
' 単一ファイルの変換
'------------------------------------------------------------------------------
Public Sub ConvertDecimalToDouble_SingleFile()
    Dim inputPath As String
    Dim outputPath As String
    Dim fso As Object
    
    ' ファイル選択ダイアログ
    With Application.FileDialog(msoFileDialogFilePicker)
        .Title = "変換対象のファイルを選択してください"
        .Filters.Clear
        .Filters.Add "Python Files", "*.py"
        .Filters.Add "Scala Files", "*.scala"
        .Filters.Add "JSON Files", "*.json"
        .Filters.Add "All Files", "*.*"
        If .Show = -1 Then
            inputPath = .SelectedItems(1)
        Else
            MsgBox "キャンセルされました。", vbInformation
            Exit Sub
        End If
    End With
    
    Set fso = CreateObject("Scripting.FileSystemObject")
    
    ' 出力ファイルパス生成
    Dim baseName As String
    Dim ext As String
    baseName = fso.GetBaseName(inputPath)
    ext = fso.GetExtensionName(inputPath)
    outputPath = fso.GetParentFolderName(inputPath) & "\" & baseName & "_converted." & ext
    
    ' 変換実行
    If ConvertFile(inputPath, outputPath) Then
        MsgBox "変換完了!" & vbCrLf & "出力先: " & outputPath, vbInformation
    Else
        MsgBox "変換に失敗しました。", vbExclamation
    End If
    
    Set fso = Nothing
End Sub

'------------------------------------------------------------------------------
' ファイル変換処理
'------------------------------------------------------------------------------
Private Function ConvertFile(inputPath As String, outputPath As String) As Boolean
    On Error GoTo ErrorHandler
    
    Dim fso As Object
    Dim inputFile As Object
    Dim outputFile As Object
    Dim content As String
    Dim convertedContent As String
    Dim changeLog As String
    
    Set fso = CreateObject("Scripting.FileSystemObject")
    
    ' ファイル読み込み (UTF-8対応)
    content = ReadFileUTF8(inputPath)
    
    ' 変換実行
    convertedContent = ConvertDecimalTypes(content, changeLog)
    
    ' ファイル出力 (UTF-8)
    WriteFileUTF8 outputPath, convertedContent
    
    ' 変更ログをデバッグ出力
    If Len(changeLog) > 0 Then
        Debug.Print "=== " & inputPath & " ==="
        Debug.Print changeLog
    End If
    
    ConvertFile = True
    Exit Function
    
ErrorHandler:
    Debug.Print "Error in ConvertFile: " & Err.Description
    ConvertFile = False
End Function

'------------------------------------------------------------------------------
' Decimal型からDouble型への変換ロジック
'------------------------------------------------------------------------------
Private Function ConvertDecimalTypes(content As String, ByRef changeLog As String) As String
    Dim result As String
    Dim patterns As Variant
    Dim replacements As Variant
    Dim i As Long
    Dim beforeCount As Long
    Dim afterCount As Long
    
    result = content
    changeLog = ""
    
    ' 変換パターン定義 (AWS Glue / PySpark / Scala 対応)
    patterns = Array( _
        "DecimalType\(\s*\d*\s*,?\s*\d*\s*\)", _
        "DecimalType\(\)", _
        "DecimalType", _
        """decimal\(\d+,\s*\d+\)""", _
        """decimal""", _
        "'decimal\(\d+,\s*\d+\)'", _
        "'decimal'", _
        "decimal\(\d+,\s*\d+\)", _
        "DataTypes\.createDecimalType\(\s*\d+\s*,\s*\d+\s*\)", _
        "DataTypes\.DecimalType", _
        "Decimal\s*\(\s*\d+\s*,\s*\d+\s*\)" _
    )
    
    replacements = Array( _
        "DoubleType()", _
        "DoubleType()", _
        "DoubleType", _
        """double""", _
        """double""", _
        "'double'", _
        "'double'", _
        "double", _
        "DataTypes.DoubleType", _
        "DataTypes.DoubleType", _
        "Double" _
    )
    
    ' 正規表現による変換
    Dim regex As Object
    Set regex = CreateObject("VBScript.RegExp")
    regex.Global = True
    regex.IgnoreCase = False
    
    For i = LBound(patterns) To UBound(patterns)
        regex.Pattern = patterns(i)
        
        ' 変換前のマッチ数をカウント
        If regex.Test(result) Then
            Dim matches As Object
            Set matches = regex.Execute(result)
            changeLog = changeLog & "  " & patterns(i) & " → " & replacements(i) & _
                        " (" & matches.Count & "件)" & vbCrLf
            
            ' 置換実行
            result = regex.Replace(result, replacements(i))
        End If
    Next i
    
    ' import文の追加チェック (PySpark)
    If InStr(result, "DoubleType") > 0 And InStr(result, "from pyspark.sql.types import") > 0 Then
        If InStr(result, "DoubleType") > 0 And InStr(content, "DoubleType") = 0 Then
            changeLog = changeLog & "  ※DoubleTypeのimportが必要な場合があります" & vbCrLf
        End If
    End If
    
    Set regex = Nothing
    ConvertDecimalTypes = result
End Function

'------------------------------------------------------------------------------
' 対象ファイルかどうかを判定
'------------------------------------------------------------------------------
Private Function IsTargetFile(fileName As String, extensions As Variant) As Boolean
    Dim ext As Variant
    Dim lowerName As String
    
    lowerName = LCase(fileName)
    
    For Each ext In extensions
        If Right(lowerName, Len(ext)) = LCase(ext) Then
            IsTargetFile = True
            Exit Function
        End If
    Next ext
    
    IsTargetFile = False
End Function

'------------------------------------------------------------------------------
' UTF-8ファイル読み込み
'------------------------------------------------------------------------------
Private Function ReadFileUTF8(filePath As String) As String
    Dim stream As Object
    Set stream = CreateObject("ADODB.Stream")
    
    With stream
        .Type = 2 ' adTypeText
        .Charset = "UTF-8"
        .Open
        .LoadFromFile filePath
        ReadFileUTF8 = .ReadText
        .Close
    End With
    
    Set stream = Nothing
End Function

'------------------------------------------------------------------------------
' UTF-8ファイル書き込み (BOMなし)
'------------------------------------------------------------------------------
Private Sub WriteFileUTF8(filePath As String, content As String)
    Dim stream As Object
    Dim binaryStream As Object
    
    ' UTF-8で文字列をエンコード
    Set stream = CreateObject("ADODB.Stream")
    With stream
        .Type = 2 ' adTypeText
        .Charset = "UTF-8"
        .Open
        .WriteText content
        .Position = 0
        .Type = 1 ' adTypeBinary
        .Position = 3 ' BOMスキップ
        
        ' BOMなしで保存
        Set binaryStream = CreateObject("ADODB.Stream")
        binaryStream.Type = 1 ' adTypeBinary
        binaryStream.Open
        binaryStream.Write .Read
        binaryStream.SaveToFile filePath, 2 ' adSaveCreateOverWrite
        binaryStream.Close
        
        .Close
    End With
    
    Set stream = Nothing
    Set binaryStream = Nothing
End Sub

'------------------------------------------------------------------------------
' プレビュー機能: 変換結果をシートに出力
'------------------------------------------------------------------------------
Public Sub PreviewConversion()
    Dim inputPath As String
    Dim content As String
    Dim convertedContent As String
    Dim changeLog As String
    Dim ws As Worksheet
    
    ' ファイル選択
    With Application.FileDialog(msoFileDialogFilePicker)
        .Title = "プレビューするファイルを選択してください"
        .Filters.Clear
        .Filters.Add "Python Files", "*.py"
        .Filters.Add "Scala Files", "*.scala"
        .Filters.Add "JSON Files", "*.json"
        .Filters.Add "All Files", "*.*"
        If .Show = -1 Then
            inputPath = .SelectedItems(1)
        Else
            Exit Sub
        End If
    End With
    
    ' ファイル読み込みと変換
    content = ReadFileUTF8(inputPath)
    convertedContent = ConvertDecimalTypes(content, changeLog)
    
    ' 新しいシートに出力
    Set ws = ThisWorkbook.Worksheets.Add
    ws.Name = "Preview_" & Format(Now, "hhnnss")
    
    ' ヘッダー
    ws.Range("A1").Value = "変換前"
    ws.Range("B1").Value = "変換後"
    ws.Range("C1").Value = "変更内容"
    
    ' 内容
    ws.Range("A2").Value = content
    ws.Range("B2").Value = convertedContent
    ws.Range("C2").Value = changeLog
    
    ' 書式設定
    ws.Columns("A:C").ColumnWidth = 80
    ws.Rows("2").WrapText = True
    ws.Range("A1:C1").Font.Bold = True
    
    MsgBox "プレビューをシートに出力しました。", vbInformation
End Sub

'------------------------------------------------------------------------------
' カスタムパターン追加機能
'------------------------------------------------------------------------------
Public Sub ConvertWithCustomPatterns()
    Dim inputPath As String
    Dim outputPath As String
    Dim content As String
    Dim convertedContent As String
    Dim customPattern As String
    Dim customReplacement As String
    Dim fso As Object
    Dim regex As Object
    
    ' ファイル選択
    With Application.FileDialog(msoFileDialogFilePicker)
        .Title = "変換対象のファイルを選択してください"
        If .Show = -1 Then
            inputPath = .SelectedItems(1)
        Else
            Exit Sub
        End If
    End With
    
    ' カスタムパターン入力
    customPattern = InputBox("追加の検索パターン (正規表現):" & vbCrLf & _
                            "例: numeric\(\d+,\s*\d+\)", "カスタムパターン")
    If customPattern = "" Then
        MsgBox "標準パターンのみで変換します。", vbInformation
    Else
        customReplacement = InputBox("置換文字列:", "置換先", "double")
    End If
    
    Set fso = CreateObject("Scripting.FileSystemObject")
    
    ' ファイル読み込み
    content = ReadFileUTF8(inputPath)
    
    ' 標準変換
    Dim changeLog As String
    convertedContent = ConvertDecimalTypes(content, changeLog)
    
    ' カスタムパターン適用
    If customPattern <> "" Then
        Set regex = CreateObject("VBScript.RegExp")
        regex.Global = True
        regex.Pattern = customPattern
        
        If regex.Test(convertedContent) Then
            Dim matches As Object
            Set matches = regex.Execute(convertedContent)
            changeLog = changeLog & "  [カスタム] " & customPattern & " → " & _
                        customReplacement & " (" & matches.Count & "件)" & vbCrLf
            convertedContent = regex.Replace(convertedContent, customReplacement)
        End If
        
        Set regex = Nothing
    End If
    
    ' 出力
    Dim baseName As String
    Dim ext As String
    baseName = fso.GetBaseName(inputPath)
    ext = fso.GetExtensionName(inputPath)
    outputPath = fso.GetParentFolderName(inputPath) & "\" & baseName & "_converted." & ext
    
    WriteFileUTF8 outputPath, convertedContent
    
    MsgBox "変換完了!" & vbCrLf & vbCrLf & _
           "変更内容:" & vbCrLf & changeLog & vbCrLf & _
           "出力先: " & outputPath, vbInformation
    
    Set fso = Nothing
End Sub

使い方

1. VBAモジュールのインポート

  1. Excelを開き、Alt + F11 でVBAエディタを起動
  2. メニューから「ファイル」→「ファイルのインポート」を選択
  3. ダウンロードした .bas ファイルを選択

2. マクロの実行

  1. Alt + F8 でマクロ一覧を表示
  2. 実行したいマクロを選択して「実行」

3. フォルダ一括変換の場合

1. ConvertDecimalToDouble_Folder を実行
2. 変換対象のフォルダを選択
3. 変換完了後、converted_yyyymmdd_hhnnss フォルダに出力される

4. プレビュー機能

変換前に結果を確認したい場合は PreviewConversion を使用します。

変換前後の内容と変更ログがExcelシートに出力されるため、安心して本番変換を実行できます。

カスタムパターンの追加

プロジェクト固有の型定義がある場合、ConvertWithCustomPatterns で追加の正規表現パターンを指定できます。

例: numeric(\d+,\s*\d+) → double

注意事項

import文の確認

PySpark の場合、DecimalType から DoubleType に変換すると、import文の修正が必要になる場合があります。

# 変換前
from pyspark.sql.types import StructType, StructField, DecimalType

# 変換後(手動で修正が必要)
from pyspark.sql.types import StructType, StructField, DoubleType

変換ログに警告が出力されるので、確認してください。

精度の違い

Decimal型とDouble型では精度が異なります。金融系など高精度が必要な場面では、変換による影響を十分に検討してください。

精度 用途
Decimal(38,18) 最大38桁 金融計算、会計処理
Double 約15-17桁 科学計算、一般的な数値処理

バックアップ

変換前のファイルは上書きされませんが、念のため事前にバックアップを取ることをお勧めします。

動作環境

  • Microsoft Excel 2016以降
  • Windows 10/11
  • VBScript.RegExp(標準搭載)
  • ADODB.Stream(標準搭載)

まとめ

AWS Glueのデータパイプライン開発において、型変換は地味ながら重要な作業です。本ツールを使うことで、以下のメリットがあります。

  • ✅ 手作業による見落としを防止
  • ✅ 複数ファイルを一括処理
  • ✅ 変更ログで何が変換されたか把握可能
  • ✅ プレビュー機能で安全に確認

ぜひ活用してみてください!

参考リンク


最後までお読みいただきありがとうございました。
いいねやストックをいただけると励みになります!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?