Re:SALOON & VBA

ORACLE DB(UTF8) から EXCELダウンロード

ADO で、ORACLE からSELECTしていましたが、
UTF8で外字などがあると、(勝手に)SJIS変換して字化けします。
いろいろ、ネットで解決策を探したのですが、残念ながら見つからず
(解決策ありましたら、ご指導ください。)

SQLPLUS で、CSVへは、UTF8のまま落とせる方法を見つけたため
1.BATファイルを作成する
2.SQLファイルを作成する
3.BATを起動する(SQLPLUS実行==>CSVを作成)
4.CSVをEXCELでUTF8で読み込む
5.BAT,SQL,CSVファイルを削除する
という手順を考えました。↓ どうでしょうか?(一案ということで)

■シート(sheet1)は、データ展開用に先頭に空けておく

■シート(BAT)
@ECHO OFF
SET FILE_NAME=%~n0
SET NLS_LANG=Japanese_Japan.AL32UTF8
SQLPLUS -S ORCL_USER/ORCL_PASS@ORCL_DSN @%FILE_NAME%.SQL "%FILE_NAME%.CSV"
EXIT

■シート(SQL)
TTITLE OFF;
BTITLE OFF;
SET TRIM ON;
SET ECHO OFF;
SET NEWPAGE 0;
SET PAGESIZE 0;
SET COLSEP ",";
SET VERIFY OFF;
SET HEADING OFF;
SET TERMOUT OFF;
SET FEEDBACK OFF;
SET EMBEDDED OFF;
SET LINESIZE 999;
SET TRIMSPOOL OFF;

SPOOL &1;

SELECT '社員番号,カナ氏名,氏名,生年月日,性,住所' FROM DUAL;

SELECT RTRIM(MEMBERNO,' ') || ',' ||
    RTRIM(KANA  ,' ') || ',' ||
    RTRIM(SIMEI  ,' ') || ',' ||
    RTRIM(BYMD  ,' ') || ',' ||
    RTRIM(SEX   ,' ') || ',' ||
    RTRIM(ADRS  ,' ')
 FROM SYAIN_TBL
WHERE OFFYMD IS NOT NULL
ORDER BY MEMBERNO;

SPOOL OFF;

EXIT;

■VBA
Option Explicit

Private Sub Workbook_open()
 Dim strFileName As String
 Dim intFileNo  As Integer
 Dim ret     As Long
 Dim i      As Long
 Dim MaxRow   As Long
 Dim Bytes    As Variant

 strFileName = Replace(ThisWorkbook.Name, "xlsm", "")
 ChDrive ThisWorkbook.Path
 ChDir ThisWorkbook.Path

 On Error Resume Next
' BATファイルの書出し
 Sheets("BAT").Select
 Sheets("BAT").Cells(1, 1).Select
 MaxRow = ActiveCell.SpecialCells(xlCellTypeLastCell).Row
 intFileNo = FreeFile
 Open strFileName & "BAT" For Output As #intFileNo
 For i = 1 To MaxRow
  Print #intFileNo, Sheets("BAT").Cells(i, 1).Value
 Next i
 Close #intFileNo
 If Err.Number > 0 Then
  MsgBox "BATファイル作成に失敗しました"
  Exit Sub
 End If

' SQLファイルの書出し
 Sheets("SQL").Select
 Sheets("SQL").Cells(1, 1).Select
 MaxRow = ActiveCell.SpecialCells(xlCellTypeLastCell).Row
 With CreateObject("ADODB.Stream")
  .Type = adTypeText
  .Charset = "utf-8"
  .Open
  For i = 1 To MaxRow
   .WriteText Sheets("SQL").Cells(i, 1).Value, adWriteLine
  Next i
  .Position = 0
  .Type = adTypeBinary
  .Position = 3
  Bytes = .Read
  .Close
 End With
 With CreateObject("ADODB.Stream")
  .Type = adTypeBinary
  .Open
  .Position = 0
  .Write Bytes
  .SaveToFile strFileName & "SQL", adSaveCreateOverWrite
  .Close
 End With
 If Err.Number > 0 Then
  MsgBox "SQLファイル作成に失敗しました"
  Exit Sub
 End If

 Worksheets(1).Select

' BATの起動
 With CreateObject("Wscript.shell")
  ret = .Run(strFileName & "BAT", 1, True)
  If Err.Number > 0 Or ret <> 0 Then
   MsgBox "BAT起動・実行に失敗しました"
   Exit Sub
  End If
 End With

' CSVファイル(UTF8)の読込み
 With ActiveSheet.QueryTables.Add(Connection:="text;" & _
    strFileName & "CSV", Destination:=Range("A1"))
  .TextFilePlatform = 65001
  .TextFileCommaDelimiter = True
  .Refresh BackgroundQuery:=False
  .Delete
 End With

' XLSファイルの書出し
 Worksheets(1).Move
 ActiveWorkbook.SaveAs Filename:=strFileName & "xls", FileFormat:=xlExcel8
 If Err.Number > 0 Then
  MsgBox "保存されませんでした"
  Exit Sub
 End If

' 後始末
 Kill strFileName & "BAT"
 Kill strFileName & "SQL"
 Kill strFileName & "CSV"

 ThisWorkbook.Close SaveChanges:=False

End Sub

※テーブルは、架空のため、実は動作確認していません。
 もし、バグがありましたら、コメントください。
 (辛らつなご指摘はご容赦ください。心がすぐ折れます!)

コメント一覧

ブログオーナー
無意味でした
いろいろやって、出来るようになったものの
最近、ACCESS経由(中継)で、
ORACLEをADODBで引っ張ったところ
字化けしないことに気付きました。
あれれ・・・

じゃあ、ODBCで検索すると化けないのでは・・・
と思い、
ODBCでORACLE OPEN したところ
ちゃんとUTF8のまま検索可能・・・

ありゅあ・・・

お騒がせしました。

まあ、batch起動の勉強にはなりましたが・・・
ブログオーナー
改良版③
(②から続く)

■シート:sheet1
 展開用として、ブランクシートを先頭に設定

■シート:BAT
@ECHO OFF

:ファイル名取得
SET FILE_NAME=%~n0
TITLE %FILE_NAME%

:オラクル情報設定
SET ORCL_USER=DUMMY
SET ORCL_PASS=DUMMY
SET ORCL_DSN=DUMMY

ECHO ━━━━━━━━━━━━
ECHO ORACLE 接続情報
ECHO ━━━━━━━━━━━━
ECHO ユーザー  = %ORCL_USER%
ECHO サービス名 = %ORCL_DSN%

ECHO ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ECHO ■【 START 】 %FILE_NAME%  %DATE% %TIME%

SET NLS_LANG=Japanese_Japan.AL32UTF8

SQLPLUS -S %ORCL_USER%/%ORCL_PASS%@%ORCL_DSN% @%FILE_NAME%.SQL "%FILE_NAME%.CSV"

IF ERRORLEVEL 1 GETO ABORT

:END

ECHO ■【 N-END 】 %FILE_NAME%  %DATE% %TIME%
ECHO ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GOTO QUIT

:ABORT
ECHO ××××××××××××××××××××××××××××××××××××××
ECHO ABNORMAL_END!!!    %FILE_NAME%  %DATE% %TIME%
ECHO ××××××××××××××××××××××××××××××××××××××
ECHO ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

:QUITE

EXIT

■シート:SQL
TTITLE OFF;
BTITLE OFF;
SET TRIM ON;
SET ECHO OFF;
SET NEWPAGE 0;
SET PAGESIZE 0;
SET COLSEP ",";
SET VERIFY OFF;
SET HEADING OFF;
SET TERMOUT OFF;
SET FEEDBACK OFF;
SET EMBEDDED OFF;
SET LINESIZE 999;
SET TRIMSPOOL ON;

COLUMN NAME FORMAT a16
COLUMN JUSYO FORMAT a40

SPOOL &1;

SELECT '社員№,部CD,課CD,カナ,氏名,性,生年月日,〒,住所,電話,入社日,摘要,廃' FROM DUAL;

SELECT SYAINNO
   ,BUCD
   ,KACD
   ,KANA
   ,NAME
   ,SEX
   ,TO_CHAR(BYMD,'YYYY/MM/DD')
   ,YUBIN
   ,JUSYO
   ,TEL
   ,TO_CHAR(INYMD,'YYYY/MM/DD')
   ,REPLACE(TEKIYO,CHR(13) || CHR(10),'@CR@')
   ,HAISIFLG
FROM SYAIN_MST
WHERE BUCD = 12
  AND HAISIFLG = 0
ORDER BY KACD,SYAINNO;

SPOOL OFF;

EXIT;
ブログオーナー
改良版②
(①から続く)

' TEXTファイルの書出し
Private Sub TextFileOut(pSheetName As String, pFilename As String, pRet As Long)
 Dim MaxRow  As Long
 Dim i     As Long
 Dim intFileNo As Integer
 Dim strUser  As String
 Dim strPass  As String
 Dim strDSN  As String

 Sheets(pSheetName).Select
 Cells(1, 1).Select
 MaxRow = ActiveCell.SpecialCells(xlCellTypeLastCell).Row
 intFileNo = FreeFile
 Open pFilename For Output As #intFileNo
 For i = 1 To MaxRow
  ' セキュリティ確保の為、実行時にログイン情報を入力の場合、置換
  Select Case Cells(i, 1).Value
   Case "SET ORCL_USER=DUMMY"
    Cells(i, 1).Select
    strUser = InputBox("Oracle User ?")
    Print #intFileNo, "SET ORCL_USER=" & strUser
   Case "SET ORCL_PASS=DUMMY"
    Cells(i, 1).Select
    strPass = InputBox("Oracle User PassWord ?")
    If strPass = "" Then
     strPass = strUser & "000"
    End If
    Print #intFileNo, "SET ORCL_PASS=" & strPass
   Case "SET ORCL_DSN=DUMMY"
    Cells(i, 1).Select
    strDSN = GetDSN(Cells(i, 5).Value)
    If Cells(i, 5).Value UserForm1.ListBox1.ListIndex Then
     Cells(i, 5).Value = UserForm1.ListBox1.ListIndex
     On Error Resume Next
     Worksheets(1).Select
     ThisWorkbook.Save
     Err.Clear
    End If
    If strDSN = "" Then
     MsgBox "DSN未設定です"
    Else
     Print #intFileNo, "SET ORCL_DSN=" & strDSN
    End If
   Case Else
    Print #intFileNo, Sheets(pSheetName).Cells(i, 1).Value
  End Select
  If Left(Cells(i, 1).Value, 14) = "SET ORCL_USER=" Then
   strUser = Mid(Cells(i, 1).Value, 15)
  End If
 Next i
 Close #intFileNo
 pRet = Err.Number
End Sub

' UTF-8ファイルの書出し(BOMなし)
Private Sub UTF8FileOut(pSheetName As String, pFilename As String, pRet As Long)
 Dim MaxRow As Long
 Dim i    As Long
 Dim Bytes  As Variant

 Sheets(pSheetName).Select
 Cells(1, 1).Select
 MaxRow = ActiveCell.SpecialCells(xlCellTypeLastCell).Row
 With CreateObject("ADODB.Stream")
  .Type = adTypeText
  .Charset = "utf-8"
  .Open
  For i = 1 To MaxRow
   .WriteText Sheets(pSheetName).Cells(i, 1).Value, adWriteLine
  Next i
  .Position = 0
  .Type = adTypeBinary
  .Position = 3
  Bytes = .Read
  .Close
 End With
 With CreateObject("ADODB.Stream")
  .Type = adTypeBinary
  .Open
  .Position = 0
  .Write Bytes
  .SaveToFile pFilename, adSaveCreateOverWrite
  .Close
 End With
 pRet = Err.Number
End Sub

' 改行マークの戻し、余白の削除
Private Sub NewLineChange()
 Dim i   As Long
 Dim j   As Long
 Dim MaxCol As Long
 Dim MaxRow As Long

 Cells(1, 1).Select
 MaxCol = ActiveCell.SpecialCells(xlCellTypeLastCell).Column
 MaxRow = ActiveCell.SpecialCells(xlCellTypeLastCell).Row
 For i = 1 To MaxCol
  For j = 1 To MaxRow
   If InStr(Cells(j, i).Value, "@CR@") > 0 Then
    Cells(j, i).Value = RTrim(Replace(Cells(j, i).Value, "@CR@", vbNewLine))
   Else
    Cells(j, i).Value = Trim(Cells(j, i).Value)
   End If
  Next j
  Columns(i).AutoFit
 Next i
End Sub

' サービス名をtnsnames.oraから取得し、リストボックスで選択させる
Private Function GetDSN(idx As Integer) As String
 Dim i     As Long: i = 0
 Dim buf    As String
 Dim strDSN  As String
 Dim intFileNo As Integer
 Dim ret    As Integer

 intFileNo = FreeFile
 Open ORA_HOME & "NETWORK\ADMIN\tnsnames.ora" For Input As intFileNo
 Do Until EOF(intFileNo)
  Line Input #intFileNo, buf
  Select Case Left(Trim(buf), 1) 'tnsnames.oraの記述形式により工夫する
   Case "#"
   Case "("
   Case ")"
   Case ""
   Case Else
    strDSN = Trim(Replace(buf, "=", ""))
    UserForm1.ListBox1.AddItem strDSN
    i = i + 1
  End Select
 Loop
 If idx < i Then
  UserForm1.ListBox1.ListIndex = idx
 End If
 Close #intFileNo
 If i = 1 Then
  GetDSN = strDSN
  Exit Function
 End If
 UserForm1.Show
 If UserForm1.ListBox1.Value "" Then
  GetDSN = UserForm1.ListBox1.Value
 End If
End Function

' 罫線描画
Private Sub BorderAdd()
 Dim MaxCol As Long
 Dim MaxRow As Long

 Worksheets(1).Select

 Cells(1, 1).Select
 MaxCol = ActiveCell.SpecialCells(xlCellTypeLastCell).Column
 MaxRow = ActiveCell.SpecialCells(xlCellTypeLastCell).Row

 Range(Cells(1, 1), Cells(1, MaxCol)).Interior.Color = 12611584
 Range(Cells(1, 1), Cells(MaxRow, MaxCol)).Borders.LineStyle = xlContinuous

 Cells(2, 1).Select
End Sub

' 固有編集(例えば…)
Private Sub AfterEdit()
 Select Case ThisWorkbook.Name
  Case "(このマクロブック).xlsm"
   Columns("B:C").HorizontalAlignment = xlCenter
   Columns("F:H").HorizontalAlignment = xlCenter
   Columns("K:K").HorizontalAlignment = xlCenter
 End Select
End Sub

(③に続く)
ブログオーナー
改良版①
それでも(SQL DEVELOPERでダウンロード出来ても)、
興に乗って、少しずつ改良しています。

改良点1:オラクルのログインユーザーを実行時に入力する
     環境に依存する部分を、実行時に選択で解決する。

改良点2:DSNは、TNSNAMES.ORAから取得しリストボックスにする。
     ※USERFORM1に、LISTBOX1を定義して下さい。
     かつ、ボタンを押したとき、USERFORM1をHIDEする。

改良点3:項目内に改行があるとき、CSVで改行してしまうため
     SELECTで、'@CR@'に置換し、EXCEL展開後VBNEWLINEに戻す方式。

改良点4:バッチ起動、CSV読込みでファイル書出しより速く
     読んでしまう場合がある為、ファイルの存在チェック+待ちを入れる。

改良点5:展開後のシートの整形

■VBA(ThisWorkbook)
Option Explicit

Const ORA_HOME As String = "C:\app\Administrator\product\11.2.0\dbhome_1"

Private Sub Workbook_open()
 Dim strFileName As String
 Dim ret     As Long
 Dim i      As Integer

 strFileName = Replace(ThisWorkbook.Name, "xlsm", "")
 If MsgBox(strFileName & "BAT を実行します、OK?" & vbNewLine & _
             "いいえ(N):マクロ終了", _
   vbYesNo + vbQuestion, "確認") vbYes Then
   Exit Sub
 End If

 ChDrive ThisWorkbook.Path
 ChDir ThisWorkbook.Path

' ①.BATファイルの書出し
 Call TextFileOut("BAT", strFileName & "BAT", ret)
 If ret > 0 Then
  MsgBox "BATファイル作成に失敗しました"
  Exit Sub
 End If

' ②.SQLファイルの書出し
 Call UTF8FileOut("SQL", strFileName & "SQL", ret)
 If ret > 0 Then
  MsgBox "SQLファイル作成に失敗しました"
  Exit Sub
 End If

' ③.BATの起動
 ret = Shell(ThisWorkbook.Path & "" & strFileName & "BAT", 1)
 On Error Resume Next
 i = 0
 Do While Dir(strFileName & "BAT") = ""
  i = i + 1
  Application.StatusBar = "BATファイル読込み待ち..." & i & "/10 回目"
  If i > 10 Then
    MsgBox "BATファイルが存在しません"
    Exit Sub
  End If
 Loop
 If Err.Number > 0 Then
  MsgBox "BAT実行が失敗しました"
  Exit Sub
 End If

' ④.CSVファイル(UTF8)の読込み
 Worksheets(1).Select
 On Error Resume Next
 i = 0
 Do While Dir(strFileName & "CSV") = ""
  i = i + 1
  Application.StatusBar = "CSVファイル読込み待ち..." & i & "/10 回目"
  If i > 10 Then
    MsgBox "CSVファイルが存在しません"
    Exit Sub
  End If
 Loop
 With ActiveSheet.QueryTables.Add(Connection:="text;" & _
    strFileName & "CSV", Destination:=Range("A1"))
   .TextFilePlatform = 65001
   .TextFileCommaDelimiter = True
   .Refresh BackgroundQuery:=False
   .Delete
 End With
 If Err.Number > 0 Then
  MsgBox "CSVファイル(UTF8)の読込みに失敗しました" & vbNewLine & _
      Err.Number & ":" & Err.Description
  Exit Sub
 End If
 Loop

' ⑤.改行コードの置換
 Application.ScreenUpdating = False
 Call NewLineChange
 Call BorderAdd

' ⑥.XLSファイルの書出し
 Worksheets(1).Move
 Call AfterEdit
 On Error Resume Next
 ActiveWorkbook.SaveAs Filename:=strFileName & "xls", FileFormat:=xlExcel8
 If Err.Number > 0 Then
  MsgBox "保存されませんでした"
  Exit Sub
 End If

' ⑦.後始末
 Kill strFileName & "BAT"
 Kill strFileName & "SQL"
 Kill strFileName & "CSV"

 ThisWorkbook.Close SaveChanges:=False

End Sub

(②に続く)
ブログオーナー
あれれ・・・
仕事で資料作成にEXCELとVBAを使っています。
EXCELのVBAではなく、EXCELとVBAなのは、もっぱらEXCELがメインで、
VBAは、余技というか、余分というか・・・
必須ではないが、あったら便利でしょぐらいで、
無ければ無いで、地道に編集すればいいこと。

このEXCELダウンロードの仕組みも、SJISで字化けしても、
SJISなんで、化けてますけど・・・と言い訳すれば済むこと。
勿論、それが許されない資料ならプログラム作ったり、
その程度です。

ORACLEデータのEXCEL化も通常は、SI Object Browserでやってます。
但し、ヴァージョンが低いので、UTF-8非対応なのです。
そして、EXCELの方で定常的な編集が必要なもので、VBA(ADO)を使うのですが、
こっちも、UTF-8の対応が不明なのです。

で、SQLPLUSだったら、化けずにCSVに出来る。
CSVだったら、ECXELも化けずに取り込めるということで、
このEXCELダウンロードの仕組みを作ってみたという訳です。

ところが、・・・です。
今日、会社で、
ORACLEについている、SQL DEVELOPERで、
(いつもは、有償のSI Object Browserを使うのでこっちは使わない)
EXCEL出力機能を試してみたら、(こっちは、まあまあ最新Verです)
出来るじゃないですか、・・・

あれれ・・・難しい仕組みいらないじゃん
という訳です。お粗末。
http://www.oracle.com/technetwork/jp/developer-tools/sql-developer/downloads/index.html
名前:
コメント:

※文字化け等の原因になりますので顔文字の投稿はお控えください。

コメント利用規約に同意の上コメント投稿を行ってください。

 

※ブログ作成者から承認されるまでコメントは反映されません。

  • Xでシェアする
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

最新の画像もっと見る

最近の「EXCEL VBA」カテゴリーもっと見る

最近の記事
バックナンバー
人気記事