2016年4月5日火曜日

Microsoft AccessのモジュールをVSS管理している場合のTips

VBA系のプログラムを利用して開発する場合、ソース資産等の管理にひと手間必要ですが
Accessの場合、追加ソフトを入れることでVisualSourceSafeへの接続ができるのでメモ。

今回は、Access2010です。Access2007でもできるようです。


【Access2010で使う場合に必要なソフトのインストール】


Microsoft Access 2010 ソースコード管理 をインストールするとリボンに機能が現れます
https://www.microsoft.com/ja-jp/download/details.aspx?id=6840

【VSSからデータを取得する場合】

1) Accessを起動
2) 「ソース管理」リボンにある「SourceSafeから作成」を選択するとVSSが起動する
3) VSSにてパスを指定すると、関連ファイルおよびデータベースファイルが作成される

【データをVSSから切り離す場合】


1)  リボン「ファイル」を選択「情報」から、「データベースの最適化/修復」を選択
2)  「最適化したデータベースをSource Code Controlから削除しますか?」と聞かれたら「はい」を選択

2016年4月4日月曜日

Win+MySQL5.1環境にMySQL5.7を共存させる方法

MySQL5.1で運用しているシステムがあり、検証評価のために5.7系を利用したいと思い
とりあえずとして自分で使えるWin+MySQL5.1の環境に対してMySQL5.7を導入した時のメモです。

【環境】

・Windows8 Pro(x64) + MySQL5.1(インストーラにてインストール)の環境
・MySQL5.7は公式サイトよりZipで取得


【手順】

・ダウンロードしてきたzipファイルを展開。パスは任意でよいと思いますが、私の場合ProgramFilesの中に直接ディレクトリを作って展開しました。
C:\Program Files\MySQL57

・my.iniを作成

・初期化を実施
mysqld --initialize

・コンソールにて起動

・別コンソールにてmysqlクライアントを起動

・パスワードを変更

ALTER USER 'root'@'localhost' IDENTIFIED BY 'aaaaaaaa';

・mysqld.logに記載

・コンソールの終了

・サービスとしてインストール
mysqld --install MySQL57
※サービスの削除は、mysqld --remove MySQL57

・サービスの起動
net start mysql

ひとまず起動したので、別途、マイグレーションの手順をメモしたいと思います。


2016年3月23日水曜日

MySQL 4.x系ではCREATE USERの構文が違う

ついつい忘れてしまうMySQLのCREATE USERですが、今回改めて実施したところ
はまってしまったので備忘録です。

結果としては、CREATE USER は、MySQL 5.x系からであり、MySQL4.xで実施する際には
構文が違うということでした。

NGケース


mysql> CREATE USER 'username'@'%' IDENTIFIED BY 'password';
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use near
'USER'test1'@'%' IDENTIFIED BY 'test12345'' at line 1

というわけで

OKケース


GRANT ALL PRIVILEGES ON *.* TO 'username'@'%' IDENTIFIED BY 'password';

2016年3月20日日曜日

iReportsで、グループ毎の集計値を合算して合計として表示する方法

見出しだけだとわかりづらいので例とともに。

データ例


伝票A 合計100円 , 明細 20円 30円 50円
伝票B 合計250円 , 明細 80円 170円

ここで、100円と250円を合算したい。
明細だと、一部計算がずれる場合があるので明細からの合計は行わない。


その他要件

・伝票毎で、グループが切ってある。


手順


1) Variablesを作成

 V_DENPYO_GOUKEI (名前は何でもよい) を作成、以下プロパティを設定。
 ・Cauculation : Sum
 ・Reset type : Report (これ重要)
 ・Increment Type : Group
 ・Increment group : DenpyoのGrou
 ・Variable Expression : $F{DENPYO_GOUKEI}.equals(null)? 0 : new Double($F{DENPYO_GOUKEI})

ResetTypeをReport以外に指定すると、想定値と異なる値を取得してきてしまいました。


解消できるまでに小2時間。


レポーティングツール類はプロパティの使い方が肝となることが多いと感じました。



追伸:

設定するフィールド側
text field expression : $V{V_DENPYO_GOUKEI}
Evaluation Time : Report

2016年2月22日月曜日

iReportで固定行数明細を作成する

iReportで、明細帳票を作成したい場合、シンプルにやろうとした場合にはDetailの各オブジェクトに罫線を引いて作成することが多いかと思いますが、ページの下段まで計算を引きたい場合などにはこの方法は利用できません。

Backgroundオブジェクトを利用すると、固定行数の表を持つ帳票を作ることが可能です。


【Backgroundオブジェクトの利用方法】

・Report Inspectorから、「BackGround」を選択して、「Maximize Background」をクリック
 自動でBackground用のレイアウト領域が表示されます。

その後、必要に応じてオブジェクトを配置します。

これだけで、実際のデータと関係なく、Backgroundに配置した情報が表示されるようになります。




【罫線の引き方】


もしかしたらもっと良い方法があるかもしれません。が、現状やった方法

1) 必要行数分の、横罫線をコピーペーストなどで作成する。
2) 一番上と、一番下に罫線を正規の位置(Topプロパティできっちり調整)に配置し、あとは適当においておく。
3) 全部の罫線を選択し、メニューバーの「Format」->「Vertical Spacing」->「Equal Vert Space」を選択すると、均等に配置される。



ページごとに【Background】を変える。


あまりたくさんあると大変かもしれませんが、以下のような設定で可能です。

1) 両方のオブジェクトを貼っておく。
2) Print When Expressinonに評価式を設定
  例) ($V{PAGE_NUMBER}.toString()).equals("1") ? Boolean.FALSE : Boolean.TRUE
  ⇒TRUEまたはFALSEを返す条件式が必要です。
  この式を設定した場合、2ページ目以降にしか出ないオブジェクトとなります。



【その他】

・ページ計を出したい場合
 Variablesを作成。
 例) 数量計
   Variable名:SURYO_TOTAL
   Variable Expression:$F{SURYO}.equals(null)?0:new Double($F{SURYO})
Calculation:Sum
Reset Type:Page
あとは未指定

Page Footerに、テキストを配置し、Text Field Expressionに、上記名前を割当
Text Field Expression:$V{SURYO_TOTAL}

2016年2月4日木曜日

ActiveReportsにてDistinctFieldプロパティを活用する。

【事例】

・伝票をまとめた、請求書のようなものがある。
・出力情報としては、
 ・伝票明細の情報を一覧として
 ・日毎で集計行を出力
 ・最後に、合計行を出力
・データとしては、単価金額は明細に持っていて、消費税は伝票毎に持っている。
・データ抽出処理で、伝票情報と明細情報を一緒に持ってきている。
 ⇒そのため、各明細に伝票の情報もついてくる

起きたこと
・日毎の集計行には税込みを出す必要があったので、税込みの項目をSumするのだけども
 当然ながら、複数行明細の場合にはそのままSumすると倍々になってしまう。


【対処】

・グループヘッダのプロパティにて「日」を条件とした枠を作る。
 ⇒これはまぁ普通の処理
・税込み金額を出すテキストのDistinctFieldプロパティに、「伝票番号」を指定
 SummaryFunc : DSum ←SumではなくDSum
 SummaryGroup:GroupHeaderxx
 SummaryRunning:Group
 SummaryType:SubTotal

伝票番号でDistinctしてくれて、Sumしてくれるようになりました。


ヘルプ
http://docs.grapecity.com/help/activereports-9/GrapeCity.ActiveReports.v9~GrapeCity.ActiveReports.SectionReportModel.TextBox~DistinctField.html

2016年2月1日月曜日

iReport DesignerからJaspersoft Studioへ移行が推奨されています

掲題の件

しばらく情報を追っていなかったら、iReport DesignerはJaspersoft Studioへの
移行を推奨していました。

【iReport Designer サイト】
http://community.jaspersoft.com/project/ireport-designer

英文サイトだったのでスルーしてましたが、きっちりわかりやすく書いてあります。

【JasperSoft Studio サイト】
http://community.jaspersoft.com/project/jaspersoft-studio

iReportのサイトからもリンクで飛ぶことができます。



現在の手持ち資産がiReport Designer 4.0.2で作成したころのデザイナファイルなので
そのまま移行できるかがまだわかりませんが、
なぜやろうとしたかというと、別件の技術調査でJasperReports Serverを利用する検討を
始めたからです。

JasperReports Serverに上記4.0.2のデザイナを読み込ませてみたところ、
一覧表形式でよくあるような、表のヘッダ部分に定義してあるタイトル文字が出てこなかったため
バージョンの問題だろうかと思った次第です。



この辺はJasperReports Server側の話題になるので本資料では割愛しますが
別途まとめておきたいと思います。

2015年11月28日土曜日

パスワード付きzipファイルを簡単に展開する (UNZIP利用)

掲題のとおりです。

unzipツールを利用して、パスワード付きzipファイルを簡単に展開します。

利用用等に応じて加工するとよいかと思います。

【必要ツール】

unzip.exe

以下サイトよりダウンロードできます。
http://gnuwin32.sourceforge.net/packages/unzip.htm

通常であればBinaries (Zip)でよいと思います。
展開されたデータをどこか、適当な場所へ保管します。(私の場合、d:\utility\unzip)


【バッチの作成】

SET unzipdir=d:\utility\unzip\bin\unzip.exe
%unzipdir% -o -P 展開したいパスワードを記載 %1

-oにて強制上書きしています。
-Pの後ろに、パスワードを指定します。


上記バッチファイルを保存後、バッチファイルへzipファイルをドラッグするだけです。


2015年11月25日水曜日

SugarCRMのチーム管理機能はProfessionalから

SugarCRM Community 6.5での確認結果です。

件名で答えが出てしまっていますが、SugarCRMでチーム管理を利用するには
Professionalが必要です。

詳しくはGoogleさんに「SugarCRM チーム管理 Professional」あたりで聞くと
きちんと比較しているサイトが見つかります。

【チーム管理】とは


SugarCRMのマニュアル によると、
「チーム管理オプションは安全な方法でレコードを管理するためにチームとしてユーザをグループ化するために使います。」とあります。
私が求めていた機能には、「取引先毎にチームで参照権限を分けたい」というものがあり、
これを実現できるのが「チーム管理」でした。

実際、チーム管理をきちんとしていけばそれ以上のことも勿論できるのでしょうが
今回必要な最低限の部分がレコードレベルの参照権限でした。


【で?】


結局は、「チーム」という名前のモジュールを追加して、
担当者との関連性を作り、取引先との関連性を作り、
「検索」の条件として使うというレベルで運用を開始することとしました。

レコードレベルの権限をきちっと使えるようになる前に、まずは基本的な機能で
運用をすることの優先度が高かったので、今後拡張するという方針となりました。


【結局は・・・】

件名で答えが出てしまっていますが、きちんと権限を運用するならProfessionalが必要です。
きちんとやらなくても、なんとなくでよいなら、「モジュール」を作ることで似たようなことはできます。


2015年10月30日金曜日

MySQLでWhere句を動的に変更する場合の実装・性能について

パフォーマンス改善が必要となり、Java(MyBatis)に実装されていたSQLのロジックを
分割、MySQLのプロシージャへもっていくことになりました。

MyBatisでは<if>タグやバインド変数#~により
動的にSQL(Where句)を組み立てていたのですが、同様のことを
MySQLで実施しようとすると、動的SQLの組み立てが必要となります。

プロシージャ側で動的SQLを組み立てるには文字列の結合が
必要となり、ソースコードの保守性が著しく低下するため
代替え案がないかを検証した記録を残しておきます。

【考えた代替え案】

Where句にパラメータがブランクかどうかの判断も入れてしまう
例) SELECT * FROM TABLE1 WHERE parameter1 = '' or column1 = parameter1

【先に結論】

Where句内でOrでパラメータ有無を指定しても、動的SQLでSQLを組み立てたときと
性能は変わらない。

【チューニングとしては】


サブクエリの一部を切り出して、テンポラリテーブルへ吐き出すようにして、その後に
そのクエリを利用してデータ取得をするようにしました。
このSQLのチューニングの肝としては、サブクエリが多すぎ、深すぎでMySQLでよく言われる
ところの「サブクエリ遅いよ」に対処した。ということになります。

【検証した内容】

・ダミーテーブルを準備。データは100万件。プライマリ、インデックスはあえて作らない。
・ストアドを2セット用意し、片方はパラメータブランクによるSQL、もう片方は動的SQLとする
・ダミーテーブルのカラム数が2つだと比較差異が出なかったため、カラムを10に
 増やした場合のケースも検証

【実コード】




-- テスト用テーブルの作成
drop table if exists test1;
create table test1 ( k varchar(10) , va varchar(10));

-- テスト用テーブルにデータを作成するプロシージャ
DROP PROCEDURE IF EXISTS test1createsampledate;
delimiter //
CREATE DEFINER=`root`@`localhost` PROCEDURE test1createsampledate()
BEGIN
    declare i decimal(10) default 0;
    while i <= 1000000 do
        insert into test1 values (i,i*10)
                                ,(i+1,(i+1)*10),(i+2,(i+2)*10),(i+3,(i+3)*10),(i+4,(i+4)*10),(i+5,(i+5)*10),(i+6,(i+6)*10),(i+7,(i+7)*10),(i+8,(i+8)*10),(i+9,(i+9)*10)
                                ,(i+11,(i+11)*10),(i+12,(i+12)*10),(i+13,(i+13)*10),(i+14,(i+14)*10),(i+15,(i+15)*10),(i+16,(i+16)*10),(i+17,(i+17)*10),(i+18,(i+18)*10),(i+19,(i+19)*10)
                                ,(i+21,(i+21)*10),(i+22,(i+22)*10),(i+23,(i+23)*10),(i+24,(i+24)*10),(i+25,(i+25)*10),(i+26,(i+26)*10),(i+27,(i+27)*10),(i+28,(i+28)*10),(i+29,(i+29)*10)
                                ,(i+31,(i+31)*10),(i+32,(i+32)*10),(i+33,(i+33)*10),(i+34,(i+34)*10),(i+35,(i+35)*10),(i+36,(i+36)*10),(i+37,(i+37)*10),(i+38,(i+38)*10),(i+39,(i+39)*10)
                                ,(i+41,(i+41)*10),(i+42,(i+42)*10),(i+43,(i+43)*10),(i+44,(i+44)*10),(i+45,(i+45)*10),(i+46,(i+46)*10),(i+47,(i+47)*10),(i+48,(i+48)*10),(i+49,(i+49)*10)
                                ,(i+51,(i+51)*10),(i+52,(i+52)*10),(i+53,(i+53)*10),(i+54,(i+54)*10),(i+55,(i+55)*10),(i+56,(i+56)*10),(i+57,(i+57)*10),(i+58,(i+58)*10),(i+59,(i+59)*10)
                                ,(i+61,(i+61)*10),(i+62,(i+62)*10),(i+63,(i+63)*10),(i+64,(i+64)*10),(i+65,(i+65)*10),(i+66,(i+66)*10),(i+67,(i+67)*10),(i+68,(i+68)*10),(i+69,(i+69)*10)
                                ,(i+71,(i+71)*10),(i+72,(i+72)*10),(i+73,(i+73)*10),(i+74,(i+74)*10),(i+75,(i+75)*10),(i+76,(i+76)*10),(i+77,(i+77)*10),(i+78,(i+78)*10),(i+79,(i+79)*10)
                                ,(i+81,(i+81)*10),(i+82,(i+82)*10),(i+83,(i+83)*10),(i+84,(i+84)*10),(i+85,(i+85)*10),(i+86,(i+86)*10),(i+87,(i+87)*10),(i+88,(i+88)*10),(i+89,(i+89)*10)
                                ,(i+91,(i+91)*10),(i+92,(i+92)*10),(i+93,(i+93)*10),(i+94,(i+94)*10),(i+95,(i+95)*10),(i+96,(i+96)*10),(i+97,(i+97)*10),(i+98,(i+98)*10),(i+99,(i+99)*10)
                                ;
    set i = i + 100;
    end while;
END;
//
DELIMITER ;

-- テスト用データの作成
call test1createsampledate();

-- テストデータ内容の確認
select count(*) from test1;
select * from test1 limit 0,100;


-- パラメータ=''を条件に使う
DROP PROCEDURE IF EXISTS getk;
delimiter //
CREATE DEFINER=`root`@`localhost` PROCEDURE getk( p_k varchar(10) , p_va varchar(10))
BEGIN
    SELECT * FROM test1
    WHERE k = p_k and ((p_va = '') OR va = p_va);
END;
//
DELIMITER ;

-- パラメータを元にSQLを組み立てる
DROP PROCEDURE IF EXISTS getk2;
delimiter //
CREATE DEFINER=`root`@`localhost` PROCEDURE getk2( p_k varchar(10) , p_va varchar(10))
BEGIN
    declare query varchar(4000);
    set query = CONCAT('SELECT * FROM test1 WHERE k = "' , p_k , '"');
    if (p_va <> '') THEN
        set query = CONCAT(query,' and va = "' , p_va , '"');
    end if;

    select query into @qry;
    PREPARE ddl_stmt from @qry;
    EXECUTE ddl_stmt;
    DEALLOCATE PREPARE ddl_stmt;

END;
//
DELIMITER ;

call getk('1','');
call getk2('1','');


-- 比較にならなそうなのでカラムを増やす
alter table test1 add va2 varchar(10);
alter table test1 add va3 varchar(10);
alter table test1 add va4 varchar(10);
alter table test1 add va5 varchar(10);
alter table test1 add va6 varchar(10);
alter table test1 add va7 varchar(10);
alter table test1 add va8 varchar(10);
alter table test1 add va9 varchar(10);

-- ダミーデータをセット
update test1 set
    va2 = va
   ,va3 = va
   ,va4 = va
   ,va5 = va
   ,va6 = va
   ,va7 = va
   ,va8 = va
   ,va9 = va
;

-- パラメータ=''を条件に使う
DROP PROCEDURE IF EXISTS getk_v2;
delimiter //
CREATE DEFINER=`root`@`localhost` PROCEDURE getk_v2( p_k varchar(10) , p_va varchar(10),p_va2 varchar(10),p_va3 varchar(10),p_va4 varchar(10),p_va5 varchar(10),p_va6 varchar(10),p_va7 varchar(10),p_va8 varchar(10),p_va9 varchar(10))
BEGIN
    SELECT * FROM test1
    WHERE k = p_k
        and ((p_va = '')  OR va  = p_va)
        and ((p_va2 = '') OR va2 = p_va2)
        and ((p_va3 = '') OR va3 = p_va3)
        and ((p_va4 = '') OR va4 = p_va4)
        and ((p_va5 = '') OR va5 = p_va5)
        and ((p_va6 = '') OR va6 = p_va6)
        and ((p_va7 = '') OR va7 = p_va7)
        and ((p_va8 = '') OR va8 = p_va8)
        and ((p_va9 = '') OR va9 = p_va9)
    ;
END;
//
DELIMITER ;

-- パラメータを元にSQLを組み立てる
DROP PROCEDURE IF EXISTS getk2_v2;
delimiter //
CREATE DEFINER=`root`@`localhost` PROCEDURE getk2_v2( p_k varchar(10) , p_va varchar(10),p_va2 varchar(10),p_va3 varchar(10),p_va4 varchar(10),p_va5 varchar(10),p_va6 varchar(10),p_va7 varchar(10),p_va8 varchar(10),p_va9 varchar(10))
BEGIN
    declare query varchar(4000);
    set query = CONCAT('SELECT * FROM test1 WHERE k = "' , p_k , '"');
    if (p_va <> '') THEN
        set query = CONCAT(query,' and va = "' , p_va , '"');
    end if;
    if (p_va2 <> '') THEN
        set query = CONCAT(query,' and va2 = "' , p_va2 , '"');
    end if;
    if (p_va3 <> '') THEN
        set query = CONCAT(query,' and va3 = "' , p_va3 , '"');
    end if;
    if (p_va4 <> '') THEN
        set query = CONCAT(query,' and va4 = "' , p_va4 , '"');
    end if;
    if (p_va5 <> '') THEN
        set query = CONCAT(query,' and va5 = "' , p_va5 , '"');
    end if;
    if (p_va6 <> '') THEN
        set query = CONCAT(query,' and va6 = "' , p_va6 , '"');
    end if;
    if (p_va7 <> '') THEN
        set query = CONCAT(query,' and va7 = "' , p_va7 , '"');
    end if;
    if (p_va8 <> '') THEN
        set query = CONCAT(query,' and va8 = "' , p_va8 , '"');
    end if;
    if (p_va9 <> '') THEN
        set query = CONCAT(query,' and va9 = "' , p_va9 , '"');
    end if;

    select query into @qry;
    PREPARE ddl_stmt from @qry;
    EXECUTE ddl_stmt;
    DEALLOCATE PREPARE ddl_stmt;

END;
//
DELIMITER ;

-- 項目1つ
call getk_v2('1','','','','','','','','','');
call getk2_v2('1','','','','','','','','','');

-- 項目2つ。
call getk_v2('1','','','','','','','','','');
call getk_v2('1','10','','','','','','','','');
call getk_v2('1','','10','','','','','','','');
call getk_v2('1','','','10','','','','','','');
call getk_v2('1','','','','10','','','','','');
call getk_v2('1','','','','','10','','','','');
call getk_v2('1','','','','','','10','','','');
call getk_v2('1','','','','','','','10','','');
call getk_v2('1','','','','','','','','10','');
call getk_v2('1','','','','','','','','','10');

call getk2_v2('1','','','','','','','','','');
call getk2_v2('1','10','','','','','','','','');
call getk2_v2('1','','10','','','','','','','');
call getk2_v2('1','','','10','','','','','','');
call getk2_v2('1','','','','10','','','','','');
call getk2_v2('1','','','','','10','','','','');
call getk2_v2('1','','','','','','10','','','');
call getk2_v2('1','','','','','','','10','','');
call getk2_v2('1','','','','','','','','10','');
call getk2_v2('1','','','','','','','','','10');

-- 結果どのフィールドで検索してもどちらで実装しても処理結果は変わらない