ExcelVBA覚書 CSV読込とSchema.ini

CSVファイルを読み込むときに、ADODBを使って読み込むやり方というのがあって、これには
1,ADODB.Streamを使う
2,ADODB.CommandとADODB.RecordSetのGetStringを使う(SELECT * FROM [{ファイル名}])
という2種類の方法があるというので、サンプルを実行してみたら、
1より2のほうが若干処理が速い。
ただ、2には落とし穴があって、それは
★勝手に型を変えてしまう
★読み込み方によっては正しくすべてのデータが取り込めない
ということだと分かった。

前0がついていようが数値にしよるし、日付は勝手に日付型でシートに出力されてしまうは、設定の仕方によっては思い通りのデータ取込ができなくなってしまう。

ってかさ、こんないい加減なサンプル送ってくんなよ!!
(他のところで実行時エラー起きてるし・・・)

ってなことであったが、どうすれば改善できるのか知らない私。
いろいろやってみて途方に暮れたところでGoogle先生の厄介になってみたら、

Schema.ini使うんです!

みたいな記事発見。で、「ADODB Schema.ini」で検索をかける。
ふむふむ、取り込む列の型とか、文字エンコードとか、このファイルの中で指定してあげればよいのだね!
————-
[{ファイル名}]
ColNameHeader=False
CharacterSet=65001
Format=CSVDelimited
Col1=列1 Text
Col2=列2 Text
Col3=列3 Text
Col4=列4 Text
Col5=列5 Text
—————
{ファイル名}は実際に読み込むファイル名(パスはなしで、ファイル名だけでいい)
ColNameHeader は、ヘッダー有無。(Trueはあり)
Format=CSVDelimited は、CSV形式(カンマ区切り)
CharacterSet=65001 は文字エンコードがUTF-8である。(S-JISなら932)
下に読み取り用のサンプルソースをつけているが、そこでCharacterSetを指定しているので,iniには必要ない。
(どちらかに設定があればOK)
Col1=*** の *** は、列のタイトル、その右のTextが型

【VBA】ADOを使用してテキストファイル(CSV)をDB操作する方法のまとめ

を参照したところ、型は整数はShortやLong、日付はDateと記載されている。
Char型で50文字なら、「Char Width 50」といったように記載されているので、固定長であればこういう記載になるのかと思う。
(試してはいない)

で、このSchema.iniをcsvファイルのあるフォルダパスと同じところに入れておくのだが、

チョイ待ち!!

読み込むcsvファイルが常に同じところに置かれているとは限らんではないか!
ということになった。
そう、読み込むCSVは、ダイアログで選ばせるのだ・・・
となると、csvと同じところにschema.iniを配置させねばファイルの意味がないし、いや、そもそもダイアログで選ぶファイル名もSchema.iniで定義したファイル名と異なっていたら読み込んでくれへんやん!!!

と、また1つ問題が生じてしまった。
ということで、最終的には、

a) 一時保存用のフォルダを作る
b) a)で作ったフォルダにSchema.iniを入れる
c) ダイアログで選択されたCSVファイルを a)で作成したフォルダに固定のファイル名にコピーする
  (固定のファイル名というのが、Schema.iniに定義する{ファイル名}と同じになるように)
d) c)のコピーされたほうのファイルをADODBでSELECTして読み込む
e) 読込が終わったら、c)のコピーされたほうのファイルを削除

として、どの場所にあっても、同じフォーマットで取り込まれるようにしたのだった。
ってなると、ADODB.Streamを使うより時間がかかってしまったので、結局Streamのほうが速い!という結論に至った。

とはいえ、CSVファイルの全データが取得できなかった点も、Schema.ini、Properties(“Extended Properties”)や、GetStringメソッドを見直して何とかとりあえずうまく行くようにはなった。
Officeは2016。

    Dim con As ADODB.Connection
    Dim cmd As ADODB.Command
    Dim rs  As ADODB.Recordset

    Set con = New ADODB.Connection
    With con
        .Provider = "Microsoft.ACE.OLEDB.12.0"
        .Properties("Extended Properties") = "Text;CharacterSet=65001;"    '65001=UTF-8 ,932=SJIS
        .Open {csvファイルのあるフォルダパス}
    End With
    Set cmd = New ADODB.Command
    Set cmd.ActiveConnection = con
    cmd.CommandText = "SELECT * FROM [{CSVファイル名}] "
    Set rs = New ADODB.Recordset
    rs.CursorType = adOpenStatic
    rs.Open cmd
    
    Dim dmp As String
    dmp = rs.GetString(adClipString, , ",", vbCrLf, "")  '行はCRLF, 列はカンマで区分するという設定に
    rs.MoveFirst
    Do Until rs.EOF
        '****** 1行分の処理を記載 ***********  
        rs.MoveNext
    Loop
   
  ’どばっとExcelに貼りつけるなら、Range.CopyFromRecordsetメソッドで 
    ' Activesheet.Cells(1,1).CopyFromRecordset rs            みたいな感じ

   rs.Close
    Set rs = Nothing
    Set cmd = Nothing
    con.Close
    Set con = Nothing

GetString メソッド (ADO)

中途半端なサンプルを送りつけられたせいで悩んだが、かえっていい勉強になったわぃ!
ということにしておこう。

NEW YEAR 2022

明けました。おめでとうございます。

仕事始め。
寒い。
行きたくない!けど、会議が・・・

新年早々、人一杯いる。
会社の中にも人がいっぱいいる。
オミクロン株市中感染しはじめてるってのに。

というので、なるべく会社に行かないようにしたいところ。
なのだが、会議が・・・

んでね、思うのですよ。
オミクロン株。軽症で済む人が多いっていうのはいいんですが、後遺症の話までしてほしいんですよね。
・感染者数より、重症者数。
・現時点での病床数とその利用率。
これぐらいは毎日画面に表示させてていいんじゃないの。
それから、後遺症に悩まされて仕事辞めてしまう(辞めさせられてしまう)人も多いので、
・後遺症とその対応方法がどうなっているか。
といのも報じてほしい。
感想コメントとかはいらないんで、必要な情報を流しましょう。
情報は逐次変わっていくものだし、毎日報じたって大した時間ではないでしょうよ。

と、新年早々愚痴りつつ、今年もほどほどにお仕事頑張ります。

VB.NET覚書 バックグラウンドプロセスからExcelが消えない

VB2019で、ライブラリMicrosoft.Office.Interop.Excelを使ってExcel出力を行っている。
Officeは2019だ。
COMオブジェクトなので、ReleaseComObjectでメモリ解放をしているのだが、

だが、処理が終わってもバックグラウンドプロセスからExcelが消えない・・・

リリースしてまっせ!
と思うのだが、何故か残る。

というので調べた。

・Rangeとか変数定義してるところ、リリースしてる?
 全部リリースするのよ!
・リリースはしてても時差があったりするよ!

んーーーーーー、そっか。でも頑張ってBookもSheetもRangeも処理いれたんだけど。

ということで、最後。ReleaseComObjectをぐるぐる回す。

<参照サイト>
ドリリウム『【Interop.Excel】Excelプロセス絶対殺すコード』

このサイトのWhileでReleaseComObjectを回してリリースさせるようにする!っていうのをやってみた。
とりあえず、残らなくなった気がする・・・
気がする。(ちょっと不安やけど)

VB.NET覚書 64bit AccessファイルODBC接続

客先で使うOfficeが64bitというので、普段は32bit版しか使っていない私は、トラブリューの渦に巻き込まれている。
VB.NET(Framework4.6/4.8)
ODBC接続(64bit)でAccessファイル(*.accdb)に接続
DB接続ライブラリはADODB(6.0)
 という環境を前提にしてメモ。

  1. ODBC接続(64bit)
  2. Office2019の64bit版をインストールしたにも関わらず、ODBCデータソース(64bit)の画面上にはAccess64bit用のODBC接続ドライバは表示されない。
    ネットで調べて何とか探し当てたのが
    Microsoft Access データベース エンジン 2016 再頒布可能コンポーネント
    日本語版でダウンロードしても英語版しか取得できない・・・というお粗末な状態だが、exeを実行することで、accdb形式のファイルに64bit接続ができるようになった。
    ちなみに、ADODBの2.8とかだと動かなかったので、ADODBは6.0に。

  3. VB.netでのコーディング
  4. 正直、Accessファイルじゃなかったら、64bitじゃなかったら、こんなに大変じゃないのかも・・・と思った。
    情報があまりにもない。(というか検索に引っかからないだけなのかもしれないし、検索の仕方がヘタなのかもしれないが、Accessはあっても64bitな情報じゃなかったりする。)

    • OPEN
    • Accessへの接続文字列は 「DSN=***;UID=;PWD=***;」
      DSNはODBC設定した名前。Accessなのでユーザ名は空。PWDはAccessを開くときのパスワードを設定。

      Dim conn As ADOBC.Connection = New ADOBC.Connection
      Dim ConnStr As String = "***"  '(接続文字列を設定)
      conn.ConnectionTimeout = **    '(タイムアウト秒数)
      conn.CursorLocation = ADODB.CursorLocationEnum.adUseClient  '!!!ココめっちゃ重要
      conn.Open(ConnStr)
      

      特に重要なのは、CursorLocationの設定。
      これが「adUseServer」になっていると、トランザクションの開始ができない。
      そもそもDocsを見ると初期設定はadUseClientであると書いてあるのだが、なぜadUseServerになるのだろうか。
      (ODBC設定をするときにシステムDSNでなくユーザーDSNに設定していたらいいのかな、とも思うのだが、複数ユーザで利用されることも考えてシステムDSNの設定は続行。詳細は不明。)
      【参考URL】
      Programer to Programer「Error – Attribute cannot be set now」
      トランザクション開始時に「Attribute cannot set now」のエラーが出た時にネットを探しまくったら出てきた英語のページ。
      このページの最後ぐらいに、

      This is because the RecordSet is already open. That is why we cannot participate in Begin Transaction. To overcome this problem we have to open RecordSet with the CursorLoction property as adUseClient.
      Ex .. RS.CursorLocation = adUseClient

      とあるので、試したところトランザクションが開始できるようになった。

    • CLOSE
    • 切断処理も厄介だった。閉じてもlaccdbファイルが残ってるし!!!!
      ってなって、切断直後、すぐに同じAccessファイルと接続しようとしたらエラーになってしまう現象が発生。
      これもネットで調べて、なんとなく解決させた。

      System.Runtime.InteropServices.Marshal.ReleaseComObject(conn)
      

      解放文の前に
      conn IsNot Nothing とか、System.Runtime.InteropServices.Marshal.IsComObject(conn)
      のIF文をつけておくと確実。

      laccdbのファイルを削除すればいいじゃん!みたいな記事も見たのだが、Killしてもファイル削除できなかったし、Closeしてからガベージコレクションを実行させたら何とかなるんじゃないかと思ってやってみたものの、これもダメだった。

    • 最適化
    • これはADOでなく、DAO3.6を使う。

      Dim dbe As Dao.Engine = New Dao.Engine
      dbe.CompactDatabase("元ファイル","保存ファイル",";pwd=***",Dao.DatabaseTypeEnum.dbVersion120, ";pwd=***")
      

      最適化は最適化したファイルを別名保存することになるので、最適化が済んだら、元ファイルを削除して保存ファイルをRenameする処理が後続処理として発生する。
      ここで重要なのは引数の「Dao.DatabaseTypeEnum.dbVersion120」
      Officeのバージョンによって異なるのだが、2019なのでdbVersion120にしている。
      この引数を設定していなかったときは、処理が動かなかったので、Optionな引数なくせに必須。
      パスワードがなければ、3つ目と5つ目の引数はなし。

そりゃ感染広がるでしょう

ここ何週間かで、数回飲食店で飲食をする機会があった。
飲食店にいると、マスクをつけずにしゃべってるヤツばっかり。
複数人でやってきて、食べながら会話って・・・

「マスク会食」って忘れましたか???

向かい合っている相手は家族かもしれませんが、飛沫は何mか拡散するんですよぉ~
ワクチン打ったからって、感染させないわけじゃないんですよぉ~~~

これじゃぁ、いつまで経っても酒なんか呑めないですね。

と思いながら、孤独のグルメ派な私は、一人で入って、一人で食って、イソイソ帰ってくる日々。
(というより、一緒に行く人がいないだけなのだが。)

2021 クーラーをつけた日

おお、去年は投稿を忘れていたようだ。
確か6月末だったような。

今年は今日。
温度的にはそこまで高くないのだが、やはり湿度が高い。
除湿器をつけているのだが、じめじめ感が消えないのでつけてしまった。

夏本番だなぁ。そろそろ会社に行くかな・・・

Linux覚書 yum update の取り消し

yumのupdateをしたほうがいいよ~、みたいなメッセージが出てたので、updateしたらばWebアプリの調子がおかしくなった。
しまった!、もうイチから入れなおさなあかんかなぁと思っていたが、調べてみるとupdateの巻き戻しができるようなのでやってみた。

sudo yum history

とコマンドを打って、まず履歴をチェック。

履歴がリストで出てくるので、左端にある番号、update日時からキャンセルする番号を確認。
キャンセルする番号が5ならば、

sudo yum history undo 5

とコマンドを打って実行。
途中最終確認でy/nを聞いてくるので、問題がなければyキーを打つ。

処理が正常に済んだらOK。

Webアプリとサーバを再起動させたら、update前のようにWebアプリがちゃんと動くようになった。
めでたしめでたし・・・

Qiita yumでインストールしたパッケージを取り消す

食欲の秋

阪急オアシスで「きのこと豚肉の中華風焼きそば」を買ってみた。
私好みの味、太めの麺でちょっとカリっと香ばしいところもありおいしかった。

家からちょっと行ったところのお寺に初めて行ってみたのだが、敷地内にカフェがあって入ってみた。
注文した高菜ピラフはあっさり控えめな味でサラダもついて650円。これもうまかった。

なんだか、とっても幸せ・・・

Go To Eat Hyogo

久方ぶりに投稿。
Go To Eat 兵庫版の申し込みが10/14から!というので、さっそくアクセスしてみた。

だけど、12:00頃からアクセスしたのが悪いのか、アクセスでけへん・・・

ノートPCで幾度となくトライアルするがアクセスできない。
しょうがないから試しにスマホでアクセス。

いとも簡単に繋がる。どういうことなん?

まぁつながったからええわ。
で、まず個人情報登録。(こういうの事前に登録させることでけへんのかい!と思いつつ、登録)

現状だと、どの店舗で実施してくれるのかはわからないのと、いろんな人が使えたほうがいいと思うのとで、1冊分(1万円)だけ購入することに。(一応2冊:2万円が上限)

で、あとはハガキが届くから、自分が指定した場所でチケットを買えばよい・・・と
ふむふむ。

欲しい人皆に行きわたるようにしてくれれば、制度的には悪くはないと思うんのだが、なんだか一部の人だけが得して、結局チケットとれないまま終わる人が出てくるような仕組みに思えてならないのは気のせいだろうか。
Go To Travelも、金銭的余裕があって、時間的余裕もあって、てな人のためにある制度だし、金ってそんなところに使うもんなのかなぁ。
(往来を自由にしてもらっていいですよ、って言えば、前述の人たちは給付金なんか出さなくてもウロチョロするんでしょうから。)

と、利用しててなんだけど、ちょいと複雑な気分。

除湿機って素晴らしい

夏も冬もジメジメな日当たりの悪い部屋に住んでいる。
そうすると、青カビが窓やらカーテンやら、床やら、もう嫌がらせのように発生する。
窓に近いところに置いているものは、軒並みカビが生える。
ついでに、ほこりがたまっていると、そこにもカビが・・・

あぁ、何とかしたい。簡単に。

と思って、除湿剤やら炭やら置いているのだが、いまいち効き目がない。
なので、もう諦めて除湿機を買おうと誓って半年、いや1年か経った。

除湿機を買い渋っていた理由は、大きさと音。
大きくて重たいものは動かしにくいが、小さいとタンクも小さくなり、水を捨てる回数を考えると面倒だ。
音も気になる。うるさくて眠れない、みたいなレビューを見るとさすがに買えない。
あと、なんちゃら方式となんちゃら方式と2種類あるとかで、どっちを選ぶかも重要だ。すぐには選べない・・・

半年前にはPanasonicの除湿機を買おうと思って、価格をチラチラ見ていたのだが、やはりいいものは高い。
高くともカビが生えるよりはマシだろうと思って、ポチっとな!しようと思いつつも、やはり高い。

そんなこんなでまた梅雨の季節がやってきた。
もう、このジメジメから、本当に卒業したい!と思って、除湿機をアマゾンで調べた。

あるじゃないか。安価で、タンクの容量もそこそこ、持ち運びが億劫にならない大きさ。
アイリスオーヤマ。

ポチっとな!

やったぞ、初期不良さえなけれ・・・

早速使っております。
洗濯後は風呂場で。他は個室で。寝てるとき以外はフル稼働。
こんなに湿気てんのか!と、今まで湿気取りだけで済まそうとしていた自分の対応の悪さを反省しております。
でも、今でなかったらこの商品は出てなかったので、ちょうどよいときに買えたなぁと思った次第。
今までドライで稼働させていたエアコンも稼働時間を減らせそう。

GoogleChrome画面が真っ黒に

なった・・・
真っ黒。何もできない・・・、けど右上をクリックするとちゃんとChromeが閉じる・・・

で、Windowsを再起動してもうまくいかず。
色々調べて、最終的にはショートカットのリンク先にパラメータを渡して解決。

“C:\Program Files (x86)\Google\Chrome\Application\chrome.exe” -disable-gpu

この「-disable-gpu」をつけることでとりあえずはなんとか普通に表示されるようになった。

ORACLE覚書 階層データを引数として渡す

サマリ1
 |– 明細1-1
 |– 明細1-2
サマリ2
 |– 明細2-1

のような、階層のあるデータを引数で渡したいと思って、調べてみたらオブジェクト型なるものを発見。

で、実際にどうやって実装すればいいのか、また調べて実行。

<手順>
1, まずはCREATE TYPEでもって、任意のオブジェクト型を作ってみる。

・明細データの型を作る。(Javaでいうと、データクラスみたいなもの)

CREATE TYPE DTL_TYPE AS OBJECT (
   DTL_ID   VARCHAR2(5)
   DTL_NAME VARCHAR2(10)
);

・次に作った明細(DTL_TYPE)のテーブルを型にする。(JavaでいうとList<明細>みたいなもの)

CREATE TYPE DTLTAB_TYPE AS TABLE OF DTL_TYPE;

・明細が済んだら次はサマリも同じように型を作る。

CREATE TYPE SUM_TYPE AS OBJECT (
  SUM_ID   VARCHAR2(5)
 ,SUM_NAME VARCHAR2(20)
 ,DTL      DTLTAB_TYPE
);
CREATE TYPE SUMTAB_TYPE AS TABLE OF SUM_TYPE;

2, 試しに作ったオブジェクト型を引数に、関数を作ってみる

---------------------------------------
-- 明細データをカンマ区切りで取得
---------------------------------------
CREATE OR REPLACE FUNCTION OTAMESHI_FUNC(
  PARAM IN SUMTAB_TYPE 
) 
RETURN VARCHAR
IS
  TEMP    VARCHAR(1000);
BEGIN
  -- サマリをぐるぐる回す
  DECLARE
  CURSOR CURSUM IS SELECT SUM_ID, SUM_NAME, DTL FROM TABLE(CAST(PARAM AS SUMTAB_TYPE));
  CURSUM_ROW CURSUM%ROWTYPE;
  BEGIN
    OPEN CURSUM;
    LOOP
      FETCH CURSUM INTO CURSUM_ROW;
      EXIT WHEN CURSUM%NOTFOUND;

      TEMP := TEMP || ',<<' || CUR_ROW2.SUM_ID || ':' || CUR_ROW2.SUM_ID || '>>';
      
      -- 明細をぐるぐる回す
      DECLARE
      CURSOR CUR IS SELECT DTL_ID, DTL_NAME  FROM TABLE(CAST(CURSUM_ROW.DTL AS DTLTAB_TYPE));
      CUR_ROW CUR%ROWTYPE;
      BEGIN
        OPEN CUR;
        LOOP
          FETCH CUR INTO CUR_ROW;
          EXIT WHEN CUR%NOTFOUND;

          TEMP := TEMP || ',' || CUR.DTL_ID || ':' || CUR.DTL_ID;

        END LOOP;
      END;


    END LOOP;
  END;

  -- TEMPに入れたデータを返す
  RETURN TEMP;
EXCEPTION
  WHEN OTHERS THEN
    RETURN 'エラーです.';
END;

3, 作った関数を呼び出してみる

SELECT
  OTAMESHI_FUNC(
      SUMTAB_TYPE(
        SUM_TYPE('01'
               , 'まさか'
               , DTLTAB_TYPE(
                             DTL_TYPE('A1','やさか')
                            ) 
               )
       ,SUM_TYPE('02'
               , 'どうか'
               , DTLTAB_TYPE(
                             DTL_TYPE('D1','ぎんか')
                            ,DTL_TYPE('B1','きんか')
                            ) 
               )
     )
  )
FROM DUAL

できるのは解ったのだが、う~ん、どうなんだろう。

Alexa覚書 Display表示

Displayを使ってみたくなってスキルを改修して申請したのだが、審査でNGになってしまった。

う~ん、Display表示の要素を足しただけなのになぁ・・・と思っていたら、ただ足しただけではダメっぽかった。
すいません、リファレンス読んでません。

Alexa Skills Kit Displayインターフェースのリファレンス

Qiita『Alexa ディスプレイ端末対応時にセッションをクローズする時の注意点』

審査でNGになってわかったのは、

・スキルの継続・終了とセッションの維持・破棄を明示的に合わせておくこと。
・セッションを維持させる場合は、維持させることがわかるような発話をすること。 (例えば、「ほかにないですか?」とか「もう一度教えて」とか)

で、何とか審査はパス。
お手数おかけしました。

朝から凹む

今日は夢見が悪かった。
蛇に噛まれてゾンビ化しているラスカルみたいな動物に噛まれた夢を見た。
蛇に噛まれるのも嫌だが、ゾンビ化した奴も嫌だわ。

これはきっと、YouTube?か何かで、蛇を殺して蛇皮を水入れにする動画を見たからだ…と思ったのは、会社に来る最中だった。
と、人が倒れてる。トラックの下。傍らには自転車。そして血。

巻き込まれたんだな・・・

朝から嫌なもん見たな・・・と思いつつ、本当に嫌な思いをしているのは事故の当事者だろうから、こんなこと思うのも申し訳ない思いになった。

トラックが悪いのか、自転車が悪いのかはさておき、倒れていた人が無事でありますように。
あと、事故らないように気を付けよう。

と、思って歩いてたら、逆走するは、信号は守れないは、斜め横断はするは・・・という歩行者や自転車運転手に遭遇し、辟易してしまった。
ああいうの見たら解るのかな、自分たちのしていることがどういうことか、どういうことをもたらすのか。

とにかく、周りに人がいるところは、なるべくゆっくり走ろう、と思った。
加害者にはなりたくないわ。

国土交通省近畿地方整備局 大阪国道事務所『大阪のどこで事故が多いん?』

コマンドプロンプト覚書 ゴミ箱を空に

HDDの容量を圧迫しているごみ箱の中身を削除したいのに、なんだかGUIでやると全然動作しない・・・
空にしますか?とも聞いてこない・・・

で、何とかならないのかと思ったら、コマンドプロンプト上でコマンドを打てばよいとのこと。

Cドライブのごみ箱なので、

rd /s c:\$Recycle.Bin

でやってみた。
でけた。

PowerShell覚書 ファイル操作いろいろ

最近、VBSよりPowerShellのほうをよく使うようになった。
イケてないところは多々あるものの、デバッグもしやすいので便利だ。

ファイル操作のアレコレをこの投稿にいろいろ書き足していこうと思う。
(アレコレって、漢字だと「彼是」って書くのね。知らんかった。)

【ファイル検索】
例えば、「Cドライブ」直下のファイルを漁りたいときはこんな感じ。
Get-ChildItemの戻り値を「 」(半角スペース)でSplitしてやれば、ファイル名のリストを取得できる。

$dir = "C:\";
$files = Get-ChildItem $dir;
$files_arr = $files -split " ";

【フォルダ検索】
「W」で始まる「Cドライブ」直下のディレクトリを漁りたいときはこんな感じ。
Get-ChildItemの戻り値を「 」(半角スペース)でSplitしてやれば、ディレクトリ名のリストを取得できる。
Where-Object で、「$_.PSIsContainer」を指定すればディレクトリだけを取得できる。

$dir = "C:\";
$subdir = Get-ChildItem $dir | Where-Object { $_.PSIsContainer } | Select-String "^W";
$sub_arr = $subdir -split " ";

【フォルダ・ファイル有無確認】
指定フォルダ、ファイルがあるかどうかは「Test-Path」を使う。

if (Test-Path ($dir)) {
   # あるとき
} else {
   # ないとき
}

【フォルダ作成】
フォルダ作成は「New-Item」で、パスを指定して、「-ItemType Directory」のオプションをつける。
「-Force」はすでにフォルダがあるときは、エラーにならないようにするときにつける。

New-Item $dir -ItemType Directory -Force;

【ファイルコピー】
ファイルコピーは「Copy-Item」で、コピー元のパスを指定して、「-Destination」でコピー先を指定する。
「-Force」はすでにコピー先にファイルがあっても、エラーにならないようにするときにつける。

Copy-Item $src_path -Destination $goto_path -Force;

【ファイル移動】
ファイル移動はコピーしてから削除するのがいい。
「Remove-Item」の「-Recurse」は削除対象がフォルダであれば、中のファイルを削除してからフォルダも消してくれる。
「-Force」をつければ、隠しファイルとかも消してくれるそう。

Copy-Item $src_path -Destination $goto_path -Force;
Remove-Item -Path $src_path -Recurse -Force;

【ライブラリ利用】
ライブラリは、パスを指定して読み込んでやらないと使えない。こんな感じ。

[string]$dll       = "C:\....\.....dll";
[void][reflection.assembly]::LoadFrom($dll);

PostgreSQL覚書 RETURNIG *

UPDATE、INSERT、DELETE文の最後に「RETURNING *」を加えてやると、「更新件数が返ってくる」というのをネット上で見たのだが、厳密にはどうやらそうではないらしいのでメモっておく。

INSERT .... RETURNING *

と書くとINSERTしたデータ行がすべて返ってくるのであって、件数が返ってくるわけではないのだ。
結局、

INSERT .... RETURNING {キー項目}

みたいに書いて、返ってきたデータの行数から更新件数を導きだす必要があるのだ。
だから、Javaなんかだと、SQL文を実行後のResultSetのgetRowメソッドを使う。
例)

int kensu = rs.getRow();

みたいに、返ってきたデータの行数を取得してやるのだ。

中途半端な日本語を書かれると、こういう勘違いをしてしまう。

2020年

毎度ですが、
明けました、おめでとうございます。

年末年始は相も変わらず食っちゃ寝、食っちゃ寝、の繰り返し。
しかし、今年はそれにプラスして、Amazonプライムでアニメやドラマ・映画を見ていて、結構よかった。

でも、疲れが抜けん。
そして、今日もまた仕事でミスってしまう。

と、毎年変わらぬことを繰り返しているのだが、そんだけ同じことばっかり繰り返している人生にも価値があるのだろうか・・・と少しばかり思って反省してしまう。

元日にはこれも毎年恒例の映画ファーストデーを利用した映画鑑賞をしたのだが、やはり今年はスターウォーズだ。

昔はファーストデーは1,000円で観られるから価値があったのだが、今は1,200円もする。
この200円の差は大きいな、と思いつつロビーでスナックとホットミルクティーを買ってシアターに入る。

年末に座席予約したとき、すでに上半分はほぼ埋まっていたので、仕方なく下のほうの席を取ったのだが、やっぱり角度的に下はきついなぁ、とちょっと後悔しながら予告を見る。

そして本編。
今までみたスターウォーズの中でも一番良かったんじゃないかい!!と思った。
観終わった感Maxな感じ。
(スピンオフとか作るの止めてね、ホント。もう「最後」気分味わったんで)

では、今年も「フォースと共にあらんことを」
って、なんのこっちゃ。

JavaScript覚書 JSONパース

仕事でJSONデータをバリバリ使うことになった。
けど、階層が多いからちゃんとデータ設定できているのか気になって、解析しようとJavaScriptで組むことにした。
(本当はExcelのマクロでセルにペタッと出力させたかったのだが)

<body>
    <textarea id="src"></textarea><br>
    <button onclick="javascript:return parseData();">解析</button><br>
    <pre id="res"></pre>
    
    <script>
        var doc = "";
        var indent = "&nbsp;&nbsp;";
        
        // 解析
        function parseData() {
            var srcObj = document.getElementById("src");
            var resObj = document.getElementById("res");
            doc = "";
            resObj.innerHTML = doc;
            
            var json = JSON.parse(srcObj.value);
            convJson(json, "");
            resObj.innerHTML = doc;
        }
        
        // 解析処理本体
        // obj : JSONデータ, caps : 階層表示インデント
        function convJson(obj, caps) {
            if (typeof(obj) == "object") {
                for (var i in obj) {
                    if (typeof(obj[i]) == "object") {
                        doc += caps + "[" + i + "]<br>";
                        convJson(obj[i], caps + indent);   // 下の階層を解析
                    } else {
                        doc += caps + i + " : " + obj[i] + "<br>";
                    }
                }
            } else {
                        doc += caps + i + " : " + obj[i] + "<br>";
            }
        }
    </script>
</body>