カテゴリー「仕事部屋」の77件の記事

2014年9月16日 (火)

Office: Excel2011はHTML形式ならいけそう?

昨日のエントリーの続きです。

Excel2011で外部データソースの「データベース」ボタンの利用は諦めました。
代わりと言っては何ですが、その隣の「HTML」ボタンはどうなんでしょう?

結論から言います。
SQLServerにアクセスした結果をHTML形式に加工したファイルはいい感じにインポートできました。

しかし、ここで残念なお知らせです。
HTML形式のインポート処理は安定しません。クラッシュする場合があります。

方法1. 外部データソースの「HTML」ボタンから操作 → 高確率でクラッシュ。※最悪です
方法2. メニューのファイル-インポートからHTML形式を選択 → かなり安定。
方法3. DockのアイコンにHTMLファイルをD&D → 意外と安定。

万全な方法が無いのが悔しいですわ。

僕の場合、SQLServerのデータセットはQt5から加工して出力してます。
でも、Javaが使えるなら、公式JDBC使って出力するのが一番無難かと思います。
いずれにしても、安定しない場合がある以上、お試しの方は自己責任でお願い致します。

以下、読み込みに成功したHTML形式のファイル構造について説明します。

....

まず、HTML形式のファイルは、ものすごく初歩的な最小限の構成で作成します。
データベースから取得した結果セットに見出しを付けて加工してます。

SELECT TOP 5 * FROM [NorthwindJ].[dbo].[社員]の結果を元に;

result.html:

<html>
<head>
<title>クエリーの結果</title>
</head>
<body>
<table>
<tr><th>社員コード</th><th>カタカナ</th><th>氏名</th><th>数値</th></tr>
<tr><td>105</td><td>モリウエ イクマ</td><td>森上 偉久馬</td>td>3,333.33</td></tr>
<tr><td>107</td><td>カツラギ コウシ</td><td>葛城 孝史</td><td>6,666.66</td></tr>
<tr><td>110</td><td>カトウ ヤスエ</td><td>加藤 泰江</td><td>10,000.00</td></tr>
<tr><td>204</td><td>カワムラ タダシ</td><td>川村 匡</td><td>13,333.33</td></tr>
<tr><td>207</td><td>マツザワ セイイチ</td><td>松沢 誠一</td><td>16,666.66</td></tr>
</table>
</body>
</html>

のように、至ってシンプルな構成です。

ちなみに文字コードはUTF-8で作成してます。
Safariは先頭にBOMを書かないと文字化けするのでUTF-16でも試したら、こちらでもOKでした。

このままだと味気ないので、色を付けたり表の編集もしてみました。

<th bgcolor="#EE0000"><font color="#FFFFFF">社員コード</font></th>
とか
<td bgcolor="#99CC00" align="right" nowrap>105</td>
とか

表示するテーブルのイメージが事前に固まってれば、出力時に埋め込むのもアリです。

ただし、CSSで<div><lu><li>等を操作してる表は期待通りにインポートできませんでした。
今時のHTMLで良く利用されているだけに、この辺りは空気を読んで欲しかったです。

まぁ、カンマ編集・小数点編集、右寄せ等を施した状態でインポートできたのはラッキーです。

それにしても、なんだかんだ調べてますが、不毛な感じですね。
Windows版ならQuery発行して一発で取れるのにな。

なんで、MSさんはMacから簡単にSQLServerへ接続させてくれないのかな。
Excelからだけでいいので、大目に見てくださいな。

2014年9月15日 (月)

Office: Excel2011でデータベースを扱えない

以前からMac版のExcel 2011でどうにかデータベースを扱えないものか悩んでます。

Windows版のExcelでは実に簡単に利用できる外部データソース。
ところがMac版では一筋縄ではいきません。

ちなみにもExcel 2011から外部データを取り込もうとするとこんなメッセージが表示されます。
Exceldb

簡単なメッセージですけど、ものすごく根が深いんですよね。コレって。

Macが標準で必要とするODBCドライバはiODBCドライバです。
最低限、環境はiODBCドライバを設定し、使える状態にすれば・・・って事なんですけども。

OSX10.6までなら32bitメインだし、Rosetta対応してるので、古いMSQueryがなんとか使えます。
それならOpenLinkからODBC AdministratorやiODBCのドライバを入手する方法もアリです。

残念ながら今の環境は10.9のMavericks。64bit化してRosettaには非対応。
あちこちから情報を集めましたが、ピッタリな解決策は見つかりません。
現状では、Excel2011で外部データベースを扱うのは無理だと割り切ってます。

そもそもSQLServerに関連する作業ならWindows版で完結します。
Windows版と比較して、凄まじく機能の劣るExcel2011の出る幕はないのです。
でも、せっかく購入したOfficeだし、何か良い方法はないのか考えました。

現状、JDBCやunixODBC/FreeTDSからSQLServerにアクセスして、テキストファイル化は可能です。
CSV/テキストファイルからのインポートは可能で、当然これは成功します。
しかし、当然のようにカラム属性は失われているので、微妙に嫌な感じです。

それならHTML形式では?

って事で続きはまた後日。

2014年6月 4日 (水)

Qt5: 入門Qt4〜QtSqlから使ってみる

「入門Qt4プログラミング」の13章はデータベースについてです。
Qt5環境でもテキストに従い、例題を進めます。
ただし、接続するデータベースはSQLServerです。

QtCreatorで新しいプロジェクトから「Qtウィジェットアプリケーション」を選択。
適当なプロジェクト名(ここではDBTest)を付けて、ひとまず保存。
コンパイル&実行して、空ウィンドウが表示されるのを確認。

まずは、QtSqlを利用する前に、DBTest.proファイルを編集します。

QT       += core gui sql

続いて、main.cppに関連する部分を追記します。

#include "mainwindow.h"
#include <QApplication>
#include <QMessageBox>
#include <QtSql>

bool createConnetion()
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
    db.setHostName("DB-SERVER");  // FreeTDSで記述した<サーバ名>
    db.setDatabaseName("NorthwindJ");
    db.setUserName("sa");
    db.setPassword("sql");
    if (!db.open()) {
        QMessageBox::critical(0, QObject::tr("DataBase Error"), db.lastError().text());
        return false;
    }
    return true;
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    if (!createConnetion()) {
        return 1;
    }

    QSqlQuery qry("SELECT * FROM [社員]");
    while (qry.next()) {
        QString code1 = qry.value(0).toString();
        QString name1 = qry.value(1).toString();
        QString name2 = qry.value(2).toString();
        qDebug() << qPrintable(code1) << ": " << qPrintable(name1) << ": " << qPrintable(name2);
    }

    MainWindow w;
    w.show();

    return a.exec();
}

再度コンパイル&実行すると、表示されるのはもちろん空ウィンドウです。
肝心の出力結果は「アプリケーション出力」に表示されます。

Photo

もし、こんなダイアログが表示された場合、SQLServerとの接続環境を確認してください。

Qtsqlerror

この例では、わざとパスワードを誤って設定してみました。

ここまでくれば、テキストの続きを進められると思います。
他のQtのサンプルを触って、GUIツール作ってみるのもいいかな。

2014年6月 3日 (火)

Qt5: MSSQL用ドライバを作成

ここまでの準備で、OSXからSQLServerにアクセスできる状態になりました。
しかし、残念ながら、まだQtからはアクセスできません。
QtのためにMSSQL用のデータベースドライバを作成する必要があります。

その対処方法は公式サイトのSQL Database Drivers  に記載されています。
でも、ただビルドするだけでは動きませんので、以下にポイントを書いておきます。

1. 準備するもの

(1) Qt5環境

Qt5環境はオフライン・インストーラ(dmg)からインストールしたQt 5.3.0 for Macです。
インストール時にSrcディレクトリを展開してください。でないと作業はできません。

(2) unixODBC/FreeTDSのヘッダとライブラリ

MacPortsからFreeTDSを"+mssql +odbc +universal"オプション付きでインストールします。
関連するファイルが/opt/local/includeと/opt/local/libに生成されます。
後述のqmakeでファイルが見つからない場合は、ここでミスした可能性が大きいです。

2. ドライバの生成

まずは公式サイトに従って、qmakeでMakefileを生成します。
あっさり書いてありますが、dmgからインストールした場合、とんでもなく深い階層になります。

Qt5.3.0は既定値のままホームディレクトリにインストールされているとして、

$ cd ~/Qt5.3.0/5.3/Src/qtbase/src/plugins/sqldrivers/odbc/
$ ~/Qt5.3.0/5.3/clang_64/bin/qmake "INCLUDEPATH+=/opt/local/include" "LIBS+=-L/opt/local/lib -lodbc"
$ make
$ cd ../../../../plugins/sqldrivers/

のように、ターミナルから実行します。
makeが終われば、無事にドライバが生成されているはずです。

~/Qt5.3.0/5.3/Src/qtbase/plugins/sqldrivers配下に、
libqsqlodbc.dylibとlibqsqlodbc_debug.dylibが生成されたら、次は配置です。

Qt5.3.0の動作環境では、既に同じ名前のdylibファイルが存在しています。
そのため、(お好みで)リネーム&コピーします。

$ cd ~/Qt5.3.0/5.3/clang_64/plugins/sqldrivers
$ mv libqsqlodbc.dylib libqsqlodbc.dylib.orig
$ mv libqsqlodbc_debug.dylib libqsqlodbc_debug.dylib.orig
$ cp ~/Qt5.3.0/5.3/Src/qtbase/plugins/sqldrivers/libqsqlodbc.dylib .
$ cp ~/Qt5.3.0/5.3/Src/qtbase/plugins/sqldrivers/libqsqlodbc_debug.dylib .

これで、Qt5からSQLServerにアクセスする準備が整ったと思います。

※2014.09.17追記

すみません。qmakeの後に余計な作業を書いてました。

$ make
$ make install

これでOKです。

2014年6月 2日 (月)

Qt5: MSSQLへアクセスするために

前のエントリーで、今年の2月くらいに試してた事のまとめは終わりです。
もう少し補足してもいいのですが、その前にQt5からSQLServerにアクセスしてみます。

そもそもマルチプラットホームでSQLServerにアクセスするにはどうするのがいいのかと。
敢えてSQLServerにこだわる必要はないのですが、僕のデータ資産はMSSQLなのです。
せっかく蓄積したデータを有効活用できないのは、何か悔しいのです。

Qt5からQSqlDatabaseクラスを利用するにあたり、色々と準備しないとです。
僕に適した環境を、僕が最も簡単に構築するために、MacPortsを利用します。
そして、MavericksからSQLServerにアクセスするにはFreeTDSとunixODBCが必要です。
以降、MacPortsのインストールは済んでる前提で進めます。

## /usrや/usr/local等が汚されるのは耐られないので・・・。Homebrew派の方ごめんなさい。
## OSXの初期状態はiODBC/MySQLなので、これはスルー。
## プロプラかつ有償ならこれでもいいのかな。

今回のキモはFreeTDSのインストールにあると言っても過言ではありません。
初期インストールの方はそのまま。既にインストールされた方は必ずオプションを付けて!

$ sudo port info freetds  ←ここでオプション確認
$ sudo port install freetds +mssql +odbc +universal

絶対に!絶対に!"+mssql +odbc +universal"を指定するのを忘れないでください。
これしないと、dylibが生成されません。これを忘れると、きっとハマります。
ちなみに、僕はPHP環境との併用でハマりました。

さて、目的のSQLServerにはNorthwindJがあるとします。
Windows環境から、osql -S <サーバ名> -U sa -P sqlでアクセスできるとします。
同様にMacのターミナルから、tsqlやisqlで接続する事を目指します。

でも、すみません。後述の内容は約2年前に構築済みなので、誤りがあるかもです。
手順は確かこんな感じ。まずはドライバー。

$ vi /opt/local/etc/freetds/tds.driver.template

[TDS]
Description = FreeTDS Driver for OSX & MSSQL
Driver      = /opt/local/lib/libtdsodbc.so
Setup       = /opt/local/lib/libtdsodbc.so

そしてDSN。

$ vi /opt/local/etc/freetds/tds.dsn.template

[NorthwindJ]
Driver          = TDS
Description     = DSN for NorthwindJ
Trace           = No
ServerName      = <サーバ名>
Database        = NorthwindJ
Port            = 1433
TDS_Version     = 8.0

これらをインストール。

$ sudo odbcinst -i -d -f tds.driver.template
$ sudo odbcinst -i -s -l -f tds.dsn.template

で、freetds.confを確認。

$ vi /opt/local/etc/freetds/freetds.conf

(行末に追加)
[<サーバ名>]
        host = 192.168.xxx.xxx  ; ← ここはSQLServerのIPアドレス
        port = 1433
        tds version = 8.0
        client charset = UTF-8
;       charset = CP932
;       charset = sjis
;       language = japanese

環境変数ODBCINIやFREETDSCONF辺りも調整が必要だったかも。
もう何を調整したか覚えてません。すみません。
最終的にこれがエラーにならなければ環境はOKです。

$ odbcinst -j
$ odbcinst -q -s
$ odbcinst -q -d

$ tsql -S <サーバ名> -U sa -P sql
 とか
$ isql -v NorthwindJ sa sql

以前にExcel2011のiODBCと格闘してたので、勘違いしてなきゃ良いけど。
とにかく、これでMacからODBC接続はできると思います。
SQLAllocEnv();からコツコツ書いてもいけるハズですよ。

2014年6月 1日 (日)

Qt5: 入門Qt4〜QtCreator3.1.1にて

「入門Qt4プログラング」に記述されているRADデザインツールはQt Designerでした。
Qt5.3の現在、このツールはQt Creator 3.1.1になってます。

2章で説明されている様に、Qtだとスクラッチから書いてもそんなに苦じゃありません。
それでもIDE環境から色々できたら、それはそれで便利です。

ただ、テキストの記述が随分と古く、メニュー・バーからの説明が英語表記のまま。
プラットホームの差もあるので、初期起動した直後は違和感を持つ方もいるのでは。

しかし、Qt4 → Qt5では、そんなに変化してない、って事は各所で説明されてます。
「外見が変化するダイアログ」節の内容も、よく読むとそんなに変わってないです。

Qt Creatorを起動→新しいプロジェクト→「Qtウィジェットアプリケーション」を選択。
・プロジェクト名: Sort
・クラス名: MainWindow → SortDlg
って感じで進めて、実際にデザインしてみた状態がコレ↓。

Qtdesigner

メニュー・バーが日本語表記になっているので、テキストを流してると、ちょっと迷うかも。
実際、編集メニューはこんな感じなので、

Qtdesigner_2

"Edit → Edit Widgets"って書かれても、最初はどれ?って思いました。
メニュー操作に躓かなければ、2章は大丈夫だと思います。

2014年5月29日 (木)

Qt5: 入門Qt4〜勝手にQt5 その2

入門Qt4プログラミングで勝手にQt5でやってみる、その2です。
2章からいよいよGUIプログラミングに入ります。

1章では、そのままスクラッチから書く例題でした。
2章の最初の例題もテキストに合わせて記述して、少し注意すれば動作します。
まずはQtのレイアウトマネージャの感覚を掴む、ってトコですかね。

そして、いよいよQtCreatorを使います。Qt5.3.0のはQtCreator3.1.1。
新規作成でプロジェクトを選んで・・・と。おやおや、生成されるソースの趣きが違いますね。

main.cpp側はMainWindowの生成と表示。
mainwindow.cppはコンストラクタとデストラクタのみ。
このままでもコンパイル&実行すれば、空のウィンドウが表示されます。

一応、MainWindowクラスをGoToCellDlgにリネーム。
もちろん、main.cpp側もリネームします。
後は記述されている内容から、適当にピックアップ。

自前でSIGNALに割当てるメンバ関数を"private slots:"に用意します。

class GoToCellDlg : public QDialog
{
  Q_OBJECT
public:
  explicit GoToCellDlg(QWidget *parent = 0);
  ~GoToCellDlg();
private slots:
  void on_lineEdit_textChanged();
private:
  Ui::GoToCellDlg *ui;
};

あとはuiの間接メンバとしてアクセスします。
ui->setupUi(this)やui->okButton->setEnabled(〜)って感じ。

これで、GoToCellの例題は動作すると思います。

次はいよいよデザイナですね。

2014年4月13日 (日)

Qt5: 入門Qt4〜勝手にQt5 その1

今年に入ってから、2月初旬までの間、Qt5を触ってました。

Qt5にはチュートリアルが豊富にあるので、それなりに独習できる環境にあると思います。
しかし、流行はQtQuick系とかモバイル系とか。
諸事情により、今のところ僕の目的はデスクトップ・アプリなので方向性が異なります。

書籍を探したところ、Qt5デスクトップに関するものは見つけられずじまい。
もっとも、Qt5の公式サイトには情報がみっちり書いてあるので、まあいいのです。
ずっと以前に購入したO'Reillyの「入門Qt4プログラミング」があるし。
この本と公式サイトと見比べて学習すれば、割とサクサク進むでしょう。

と、思って始めたものの、最初の一歩に手間取りました。
Qt4 → Qt5にあたり、以前と僕の前提が随分違います。
OSはUbuntu → OSX10.9に変更、QtCreatorもバージョン間で操作に差異あるし。

なので、少しだけ手間取った箇所だけ備忘録。
プラットホーム: Mac(OSX10.9) Qt5.2.1 (dmgからインストール)、QtCreator: 3.0.1
しばらくは、この環境が前提です。

まず、1章のウィジェットのレイアウト節では、いきなりのコンパイル・エラー。
Qt5公式サイトに記事があったけど、#includeだし面倒なので簡単な方法で修正。

#include <QApplication>
#include <QtWidgets>

本当は使用するWidgetsだけインクルードするのが良いのでしょうが、とりあえずはこれで。

続いて、公式サイトの記述 に従い、SIGNALとSLOTを書き換えてみます。

QObject::connect(spinBox, &QSpinBox::valueChanged, slider, &QSlider::setValue);
QObject::connect(slider, &QSlider::valueChanged, spinBox, &QSpinBox::setValue);

のように記述してみたのですが、コンパイル・エラーになってダメです。
ネットを探したら、同様に悩んでる方がいました。
そして、そこの素敵な回答 を参考にしたら、期待通りに回避できました。

QObject::connect(spinBox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), slider, &QSlider::setValue);
QObject::connect(slider, &QSlider::valueChanged, spinBox, &QSpinBox::setValue);

そっか、QSpinBoxのvalueChangedはoverloadされてるから、前のはダメだったのか。
んー、文法的にマクロより安全だろうけど、可読性が落ちるのは嫌だなぁ。
って事で、僕はケース・バイ・ケースにします。

でも、「素敵な回答」にあったけど、テンプレートで解決するのもアリですね。

2014年2月 5日 (水)

SQL: 別テーブルの内容を反映させる

少し前、同僚が悩んでました。

テーブル更新に失敗したデータベース(1)と正しい内容の古いデータベース(2)があります。
ここで、データベース(2)からローを抽出し、その内容でデータベース(1)を更新したい。

え?やっちゃえばイイじゃなーい。

まぁ、別のRDBなのは面倒なので置いといて、同じRDB内で再現してみます。
期待する結果はこんな感じ。
テーブル1にテーブル2の内容を上書きするイメージです。

Photo

この例の環境は、前回と同様にSQLServer2008R2のT-SQLです。

CREATE TABLE #tbl_temp1 (
    code        NUMERIC(2)
,   name        VARCHAR(20)
,   value       NUMERIC(3)
);
INSERT INTO #tbl_temp1 VALUES (1, 'テーブル1の1', 100);
INSERT INTO #tbl_temp1 VALUES (2, 'テーブル1の2', 200);
INSERT INTO #tbl_temp1 VALUES (3, 'テーブル1の3', 300);
INSERT INTO #tbl_temp1 VALUES (4, 'テーブル1の4', 400);

DECLARE @tbl_temp2 table (
    code        NUMERIC(2)
,   name        VARCHAR(20)
,   value       NUMERIC(3)
);
INSERT INTO @tbl_temp2 VALUES (2, 'テーブル2の2', 2);
INSERT INTO @tbl_temp2 VALUES (4, 'テーブル2の4', 4);
SELECT * FROM #tbl_temp1;
SELECT * FROM @tbl_temp2;

UPDATE A SET
    A.name = B.name
,   A.value = B.value
FROM #tbl_temp1 AS [A]
INNER JOIN @tbl_temp2 AS [B] ON A.code = B.code;

SELECT * FROM #tbl_temp1;

DROP TABLE #tbl_temp1;

前エントリーのサンプルを変えただけなので、例が悪いかもしれません。
中間テーブル(#tbl_temp1)を、テーブル変数(@tbl_temp2)の内容で上書きしてます。
実際は、どちらも普通のテーブルに置き換えてください。

別に前述の方法だけが解決策ではないので、目的を達成できるなら何でも良いとは思います。
クライアント側のアプリで実装するとか、ストアドプロシージャでサーバ・カーソル使うとか。

もし、T-SQLで済ませたい場合に、手段のひとつとしていかがでしょう。
UPDATE文でINNER JOIN使うと簡単にできますよ。

2014年1月30日 (木)

SQL: UNIONでは暗黙のソート処理あり

少し前の事ですが、同じ構造のテーブルを合成する機会がありました。
環境はSQLServer2008R2のT-SQL。

よくよく考えれば大した事じゃないのですが、備忘録を兼ねて書いておきます。

DECLARE @tbl_temp1 table (
    code        NUMERIC(2)
,   name        VARCHAR(20)
);
INSERT INTO @tbl_temp1 VALUES (1, 'テーブル1の1');
INSERT INTO @tbl_temp1 VALUES (2, 'テーブル1の2');
INSERT INTO @tbl_temp1 VALUES (3, 'テーブル1の3');

DECLARE @tbl_temp2 table (
    code        NUMERIC(2)
,   name        VARCHAR(20)
);
INSERT INTO @tbl_temp2 VALUES (2, 'テーブル2の2');
INSERT INTO @tbl_temp2 VALUES (4, 'テーブル2の4');

この様な二つテーブルからcode列に存在するデータを合成します。
期待する結果はこちら。

Sql

tbl_temp1を基準にtbl_temp2を合成しただけなので、何通りか方法はあると思います。
僕は軸となる列を列挙して、その集合に寄せる方法が好みです。 ←スタージョイン

SELECT
    *
FROM (
    SELECT DISTINCT code FROM @tbl_temp1
    UNION
    SELECT DISTINCT code FROM @tbl_temp2
) AS [A]
LEFT OUTER JOIN @tbl_temp1 AS [T1] ON T1.code = A.code
LEFT OUTER JOIN @tbl_temp2 AS [T2] ON T2.code = A.code

やりたかった事だけに絞り込むと、こんな感じのクエリーになりました。
で、とりあえずクエリーを実行してみたら、軸になる列がソート済み。

アレ?と思いつつ、色々と調べたら、UNIONでは暗黙のソート処理が走るそうで。
なーる。そう言う事でしたか。

軸となる列(ここでは両方のcode)を列挙する際、どこかにORDER BYが必要だと思ってました。
そんな訳で、この件は以後忘れないように書いておきます。

....

久しぶりの勉強部屋ネタですが、こちらでは仕事部屋にしました。
## しばらくしたら、あちらは閉鎖します。

より以前の記事一覧

2014年11月
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30            
サイト内検索
ココログ最強検索 by 暴想

Twitter

開発Twitter

無料ブログはココログ