あちこちに散らばるDBからCSV吐き出ししたい
使用者がある程度柔軟にSQLを変えられる何かが欲しいという事で作成。
WSHでJScriptはなかなか例が少ないので、何かの役に立てばと思い晒しておきます。
一応現場で動いていますが、危なっかしいかもしれません。
使用者に用意してもらうもの
2つ。
- 接続先情報
- SQL
例えば、以下の様に準備します。
接続先情報(ファイル名は、ここではnode.jsとして、confフォルダに置くものとします。)
{ "driver" : "{SQL Server}", "commandTimeOut" : 514, "uid" : "user", "pwd" : "pass", "sql" : "sql\\nodeで指定なし.sql", "node": [ {"name" : "AAA" , "server" : "XXX.XXX.XXX.XXX"}, {"name" : "BBB" , "server" : "XXX.XXX.XXX.XXX"}, {"name" : "CCC" , "server" : "XXX.XXX.XXX.XXX"}, {"name" : "DDD" , "server" : "XXX.XXX.XXX.XXX", "sql" : "sql\\DDD用.sql"}, {"name" : "EEE" , "server" : "XXX.XXX.XXX.XXX"}, {"name" : "FFF" , "server" : "XXX.XXX.XXX.XXX", "sql" : "select * from FFF"}, {"name" : "GGG" , "server" : "XXX.XXX.XXX.XXX", "sql" : "sql\\GGG用.sql"} ] }
nodeの中に個別で設定を書けば、そのnodeではそっちを優先します。
その他、設定は適時変更して下さい。(serverのXXX.XXX.XXX.XXXはIPです。コンピュータ名でも大丈夫かも。)
SQLはあくまでCSV吐き出しに使うだけなのでselect限定にして下さい。
ファイルで用意するか、接続先設定の中に直接書きます。
(.sqlで終わっている場合はSQLファイル、それ以外はSQL文そのままとみなします。)
実行するもの
JScriptです。
適当なファイル名で保存して下さい。(ここでは、getter.jsとしておきます。)
///////////////////////////////////// // 読み込む設定ファイルをここへ // // 設定ファイルは、実行ファイル // // からの相対Pathで指定して下さい。// ///////////////////////////////////// var myConfig = "conf\\node.js"; // prototype.jsのClass var Class = { create: function() { return function() { this.initialize.apply(this, arguments); } } } // Main var Main = Class.create(); Main.prototype = { initialize : function(confName) { this.confName = confName; }, execute : function() { var dao = new Dao(this.confName); var nodes = dao.getNodeNames(); // nodeで設定された宛先それぞれにSQLを発行して、 // 発行後にcallback関数を呼んでもらう for(var i = 0, len = nodes.length; i < len; i++) { dao.executeTo(nodes[i], toCsv); } } } // adoで使う定数。 // この変数名でしかうまく検索ヒットしないから書いておく。 var adClipString = 2; // Stringの拡張 String.prototype.endsWith = function(suffix) { return (suffix.length > this.length) ? false : this.lastIndexOf(suffix) == (this.length - suffix.length); } function echo(str) { WScript.Echo(str); } // Wsh特有の部分を隠蔽するクラス var WshObject = Class.create(); WshObject.prototype = { initialize : function() { this.fs = new ActiveXObject("Scripting.FileSystemObject"); this.shell = new ActiveXObject("WScript.Shell"); this.ado = new ActiveXObject("ADODB.Connection"); }, getAdoObject : function() { return this.ado; }, getCurrentPath : function() { return this.shell.currentDirectory; }, getParentPath : function() { return this.fs.getParentFolderName(WScript.ScriptFullName); }, getFileSystem : function() { return this.fs; } } // ファイル周り var File = Class.create(); File.prototype = { FOR_READING : 1, //読み込み FOR_WRITING : 2, //書きこみ(上書きモード) FOR_APPENDING : 8, //書きこみ(追記モード) initialize : function(fileName) { this.wsh = new WshObject(); this.fs = this.wsh.getFileSystem(); this.fileName = fileName; this.file = this.fs.buildPath(this.wsh.getParentPath(), this.fileName); }, openForRead : function() { return this.fs.openTextFile(this.file, this.FOR_READING); }, openForWrite : function() { return this.fs.openTextFile(this.file, this.FOR_WRITING); }, openForAppend : function() { return this.fs.openTextFile(this.file, this.FOR_APPENDING); }, readAll : function() { var reader = this.openForRead(); var str = reader.readAll(); reader.close(); return str; }, create : function() { this.fs.createTextFile(this.file); }, write : function(str) { var writer = this.openForWrite(); writer.write(str); writer.close(); }, append : function(str) { var writer = this.openForAppend(); writer.write(str); writer.close(); }, writeLine : function(str) { var writer = this.openForWrite(); writer.writeLine(str); writer.close(); }, appendLine : function(str) { var writer = this.openForAppend(); writer.writeLine(str); writer.close(); } } // 設定ファイルまわり var Config = Class.create(); Config.prototype = { initialize : function(fileName) { this.file = new File(fileName); eval("this.conf = " + this.file.readAll()); }, // Configファイルからデータを取得して値を返す。 // keyが2つ(ネスト)の場合、引数は["key1","key2"] get : function(key) { var keys = (key instanceof Array) ? key : [key]; var value; var keyStr = new String(); for(var i = 0; i < keys.length; i++) { keyStr = keyStr + "[keys[" + i + "]]"; } eval("value = this.conf" + keyStr); return value; }, getAll : function() { return this.conf; } } // データアクセスまわり var Dao = Class.create(); Dao.prototype = { initialize: function(confName) { var wsh = new WshObject(); this.ado = wsh.getAdoObject(); if(confName) { var myConf = new Config(confName); if(myConf.get("driver")) {this.driver = myConf.get("driver");} if(myConf.get("uid")) {this.uid = myConf.get("uid");} if(myConf.get("pwd")) {this.pwd = myConf.get("pwd");} if(myConf.get("sql")) {this.sql = myConf.get("sql");} if(myConf.get("commandTimeOut")) {this.timeout = myConf.get("commandTimeOut");} if(myConf.get("node")) {this.nodes = myConf.get("node");} if(myConf.get("server")) {this.server = myConf.get("server");} } }, getOpenString : function() { var str = new String(); str = str + "Driver=" + this.driver + ";" + "server=" + this.server + ";" + "uid=" + this.uid + ";" + "pwd=" + this.pwd; return str; }, open : function() { this.ado.commandTimeout = this.timeout; this.ado.open(this.getOpenString()); }, close : function() { this.ado.close(); }, execute : function(sql) { var res = this.ado.execute(sql); return res; }, executeTo : function(nodeName, callback) { var node = this.nodes[this.getNodeNumber(nodeName)]; try { if(!node) { throw("node取得に失敗しました。\nnode:" + nodeName + "の設定を確認して下さい。"); } var nodeSql = node["sql"] || this.sql; if(!nodeSql) { throw("SQL取得に失敗しました。\nnode:" + nodeName + "のSQL設定を確認して下さい。"); } var dao = this.createDaoByNode(node); dao.open(); var sqlStr = toSqlString(nodeSql); var rs = dao.execute(sqlStr); if(typeof callback == "function") { callback(nodeName, rs); } dao.close(); } catch (e) { echo("executeTo : " + e); } }, createDaoByNode : function(node) { try { var nodeServer = node["server"] || this.server; var nodeDriver = node["driver"] || this.driver; var nodeUid = node["uid"] || this.uid; var nodePwd = node["pwd"] || this.pwd; var nodeTimeOut = node["commandTimeOut"] || this.timeout; if(!nodeServer || !nodeDriver || !nodeUid || !nodePwd || !nodeTimeOut) { throw("node詳細情報取得に失敗しました。\nnodeの設定を確認して下さい。"); } var dao = new Dao(); dao.setDriver(nodeDriver); dao.setUid(nodeUid); dao.setPwd(nodePwd); dao.setServer(nodeServer); dao.setTimeOut(nodeTimeOut); return dao; } catch (e) { echo("createDaoByNode : " + e); } }, getNodeNumber : function(nodeName) { var names = this.getNodeNames(); var num = -1; for(var i = 0, len = names.length; i < len; i++) { if(nodeName == names[i]) { num = i; break; } } return num; }, getNodeNames : function() { var names = new Array(); for(var i = 0, len = this.nodes.length; i < len; i++) { names[i] = this.nodes[i]["name"]; } return names; }, setDriver : function(driver) { this.driver = driver; }, setServer : function(server) { this.server = server; }, setSql : function(sql) { this.sql = sql; }, setUid : function(uid) { this.uid = uid; }, setPwd : function(pwd) { this.pwd = pwd; }, setDriver : function(driver) { this.driver = driver; }, setNodes : function(nodes) { this.nodes = nodes; }, setTimeOut : function(timeout) { this.timeout = timeout; } } // 引数が".sql"で終わるSQLファイルだったら中身を返す。 // ".sql"で終わってなかったら引数をそのまま返す。 function toSqlString(sql) { var str = new String(); if(sql.endsWith(".sql")) { str = new File(sql).readAll(); } else { str = sql; } return str; } // レコードセットから列名を取り出してCSVへ function getHeader(rs) { var header = ""; for(var i = 0, len = rs.fields.count; i < len; i++) { var columnName = rs.fields(i).name; if(i == 0) { header = columnName; } else { header = header + "," + columnName; } } return header; } // 受け取ったレコードをCSVにする // ファイル名は、{nodeName}.csv function toCsv(nodeName, rs) { var header = getHeader(rs); var file = new File(nodeName + ".csv"); file.create(); if(!rs.Eof) { file.appendLine(header); } while(!rs.Eof) { var strRs = rs.getString(adClipString, 1000, ",", "\r\n", "NULL"); file.append(strRs); } } //////////////////////// // ここからメイン処理 // //////////////////////// var main = new Main(myConfig); main.execute();
これで準備完了。
上記例で出来あがったものは・・・
getter.js conf L node.js sql L nodeで指定なし.sql L DDD用.sql L GGG用.sql
です。
実行は、getter.jsのあるフォルダで、
cscript getter.js
とかそんな感じです。
Windows XP の場合、ダブルクリックでも実行できました。
実行すると、各nodeからデータをひっぱってきて、実行ファイルのあるフォルダにnode名.csvで吐き出されます。
ちなみに、データが1件も無い場合、0byteのファイルになります。