ご注意ください

  • 当ブログのコメントやトラックバックに、アカウントハックサイトや、そのようなサイトへリダイレクト(転送)される可能性が高いサイトへのリンクが時々貼られているようです。
    そのようなサイトへのリンクが貼られたコメント・トラックバックは、見つけ次第削除・禁止ワード登録していますが、今後も危険なサイトへのリンクが貼られる可能性がありますので、安易にリンク先へ飛ばないよう充分ご注意ください。

オンラインゲーム関連

著作権表示

  • 当ブログに記載されている
    会社名・製品名・システム名などは、
    各社の登録商標、もしくは商標です。

    当ブログ上の文章・写真・画像の
    無断転載、無断転用、直リンクなどは
    行わないでください。

    (C) 1998-2016 Vertex.
    (C) 2002-2016 SQUARE ENIX CO., LTD.
    (C) CAPCOM CO., LTD. 2007, 2016

    All Rights Reserved.
無料ブログはココログ

[MySQL] LEFT JOINがうまく動かない…?

とある在庫管理システムがあったとして、DBには4つのテーブルがあるとする。

shohin_master(商品マスタ)
maker_master(メーカーマスタ)
zaiko(在庫管理)
uriage(売上管理)

ここから、全商品に対する在庫数と売上数を抽出するVIEWを作りたかったので、以下のようなSELECT文を作ってみた。
※カラム名は実際に使っているものではなく、記事用に適当な名前をつけています

SELECT s.shohin_no, s.name, m.name, s.price, z.zaiko_num, SUM( u.uriage_num )
FROM shohin_master s, maker_master m
LEFT JOIN zaiko z ON s.shohin_no = z.shohin_no
LEFT JOIN uriage u ON z.zaiko_no = u.zaiko_no
WHERE s.shohin_no = z.shohin_no
AND s.maker_no = m.maker_no
GROUP BY z.zaiko_no;

イメージとしては、商品マスタとメーカーマスタに対して、在庫管理をLEFT JOINして、さらに売上管理をLEFT JOINしたかったのに、SELECTした結果は思い通りにはいかなかった。
つまり、
( ( shohin_master s, maker_master m ) LEFT JOIN zaiko z ) LEFT JOIN uriage u
という状況をイメージしていたのに、結果は
shohin_master s, ( maker_master m LEFT JOIN ( zaiko z LEFT JOIN uriage u ) )
となってしまっていたらしい。

どうやらMySQLでは、今までは前者で動いていたのに、いつぞやのバージョンアップ(詳しいバージョンは失念)から後者の動きになってしまったらしい?

前者のような動きをさせたかったら、明示的にカッコでくくらないといけなくなったんだとか。

そこで、FROM以降を以下のように書き換えたところ、イメージ通りの結果に。

FROM ( ( shohin_master s, maker_master m )
LEFT JOIN zaiko z ON s.shohin_no = z.shohin_no )
LEFT JOIN uriage u ON z.zaiko_no = u.zaiko_no

計算式を書くときもそうだけど、明示的にカッコでくくったほうが間違いがなくてイイヨネ。プログラムする側も、優先順位が分かりやすいし。

※記事用にSQL文を変更していますが、変更したせいで破綻したものになっていたらスミマセン(笑)

[HP-UX] PHPを動かしてOracleと接続するまで

HP-UXって、何でもかんでも独自な感じだから嫌い。でも仕事上使わざるを得ないのが辛いところ。

今回はHP-UXでPHPを動かして、さらにOracleとの接続までの設定を行ったので、手順をメモメモ。

とりあえずHP-UXは、HP-UX Itanium 11i 11.23 というもの。


まずは、/opt/hpws/apache/conf/httpd.conf を設定。PHPのモジュールがコメントアウトされているので外すだけ。環境によってはユーザーやグループの変更も必要。

#LoadModule php5_module        modules/libphp5.so
      ↓
LoadModule php5_module        modules/libphp5.so

次に、/opt/hpws/apache/conf/php.ini を設定。以下の項目を環境に合わせて編集する。コメントアウトされているものはコメントアウトを外す。今回はシフトJISを使ったので、SJISを指定している。

date.timezone = Asia/Tokyo
register_globals = On
magic_quotes_gpc = Off
default_charset = "SJIS"
mbstring.language = Japanese
mbstring.internal_encoding = SJIS
mbstring.http_input = auto
mbstring.http_output = SJIS
mbstring.encoding_translation = On
mbstring.detect_order = auto
mbstring.substitute_character = none
extension=oci8.sl

続いて、/opt/hpws/apache/bin/apachectlを修正。ライブラリパスを追加し、さらにOracle固有の設定を追加した。

#export SHLIB_PATH=$ORACLE_HOME/lib:$APACHE_PREFIX/php/lib/php/extensions:$SHLIB_PATH
      ↓
export SHLIB_PATH=$ORACLE_HOME/lib:$APACHE_PREFIX/php/lib/php/extensions:$SHLIB_PATH
export ORACLE_BASE=/opt/app/oracle
export ORACLE_HOME=$ORACLE_BASE/10.2.0/db_1
export TNS_ADMIN=$ORACLE_HOME/network/admin
export ORA_NLS33=$ORACLE_HOME/ocommon/nls/admin/data
export NLS_LANG=Japanese_Japan.JA16SJIS
export PATH=$ORACLE_HOME/bin:$PATH

この状態でapacheを再起動して接続してみると、OCILogon()がない!と怒られた。どうやらライブラリのバージョンが違うために、見つからないらしい。シンボリックリンクを張ることで対処可能。

# su - oracle
% cd /opt/app/oracle/10.2.0/db_1/lib
% ln -s libclntsh.so.10.1 libclntsh.so.9.0

もう一度apacheを再起動して、ブラウザからアクセスし、Oracleとの接続が確認できた。

Linuxとは一味違った設定方法だったので結構大変でしたが、そのぶんつながるようになったときの嬉しさは大きいかも?(笑)

余談。

apacheを自動起動にする場合は、/etc/rc.config.d/hpws_apacheconf というファイルの HPWS_APACHE_START の値を 1 にすればイイ。

[PHP] Oracleと接続するために

急遽、Oracleにデータを突っ込んでいくツールを作ることになったので、PHPにOracleと接続するための環境をセットアップしました。

そのときの手順を備忘録としてメモメモ。

いろいろやり方はあると思いますが、今回は既存の環境にできるだけ影響が出ない形でやりたかったので、peclを使ってセットアップする方法を選んでみました。

まずはOracleのサイトから、Oracle Instant Client というものをダウンロードしてくる。今回は64bitのRedHatES5だったので、「Instant Client for Linux x86-64」というところから Version 11.1.0.7.0 の rpm を全種類ダウンロード。

oracle-instantclient11.1-basic-11.1.0.7.0-1.x86_64.rpm
oracle-instantclient11.1-jdbc-11.1.0.7.0-1.x86_64.rpm
oracle-instantclient11.1-sqlplus-11.1.0.7.0-1.x86_64.rpm
oracle-instantclient11.1-devel-11.1.0.7.0-1.x86_64.rpm
oracle-instantclient11.1-tools-11.1.0.7.0-1.x86_64.rpm

今回は必要のないものもありますが、インストール先が開発マシンなので、いつか必要になるかもしれないから入れておきましょう、ということで。

さて、この開発マシンには既にPHPが入っていますが、pearやらdevelあたりが入っていないので、これらもインストール。依存関係のあるものも一緒に。

apr-devel-1.2.7-11.x86_64.rpm
apr-util-devel-1.2.7-7.el5.x86_64.rpm
httpd-devel-2.2.3-22.el5.x86_64.rpm
php-devel-5.1.6-23.el5.x86_64.rpm
php-mbstring-5.1.6-23.el5.x86_64.rpm
php-odbc-5.1.6-23.el5.x86_64.rpm
php-pdo-5.1.6-23.el5.x86_64.rpm
php-pear-1.4.9-4.el5.1.noarch.rpm

これで pecl コマンドも使えるようになるので、以下のコマンドで oci8 を作成。

# pecl install oci8

すると、なにやらエラーが…。

Fatal error: Allowed memory size of 8388608 bytes exhausted (tried to allocate 23040 bytes) in /usr/share/pear/PEAR/PackageFile/v2/Validator.php on line 692

メモリーが足りないらしい。足りないなら増やしてあげるしかないので、pearの設定にメモリ上限を指定してみる。具体的には、/usr/share/pear/pearcmd.php に以下の一行を追加。

@ini_set('memory_limit','16M');

もう一度 pecl コマンドを実行してみると、今度は成功。途中なにやら聞かれたけど、そのままエンターキーでOKっぽい。

あとは、php.ini に以下の一行を追加し、apatchを再起動して作業完了。

extension=oci8.so

これでOracle関係の関数も使えるようになったので、さーてツール作成に勤しむぞ(´Д`)

[MySQL] Oracle SQL Developper で操作

普段からDBの操作はOracle SQL Developperを使っているので、どうしてもMySQLもOracle SQL Developperで操作したくなったので、設定手順を忘れないようにメモメモ。

プライベートではphpMyAdminで事足りるけど、仕事ではやっぱりOracle SQL Developperに軍配が上がるかな…。いや、併用するのが個人的には一番イイかも。

ということで、設定手順。

Oracle SQL Developperを起動したら、メニューバーのToolsからPreferencesをクリック。

Databaseの左にある[+]をクリックして開き、Third Party JDBC Driversをクリック。

右側に開いたページの「Add Entry...」をクリックして、MySQL用のJDBCドライバを選択。自分の場合は、NetBeans6.7についてきた「mysql-connector-java-5.1.6-bin.jar」を入れてみた。

右下の「OK」をクリック。これでドライバの設定は完了。

あとはConnectionsを右クリックしてNew Connectionをクリックし、MySQLに接続するための設定をすればOK。

意外と簡単でした。

OracleにCSVファイルからインポート

DBにOracleを使ってるのに、客先からもらってきたテストデータはAccess形式だった!

とりあえずAccessからリンクさせてOracleのテーブルを参照したんだけど、テストデータをインポートしたいテーブルだけ、なぜかAccessから見えない。Table not foundになってしまう。

調べている時間もあまりないので、AccessからExcel形式でエクスポートし、Oracle SQL Developerでインポートしてしまおう!と思ってやってみると、どうもnullデータがうまく扱えないらしく、Exceptionが出てしまってお手上げ。

こうなったらしょうがない。SQL*Loaderを使ってコマンドラインからインポートするしかない!

ということで、普段やり慣れないSQL*Loaderを使ってのデータインポート方法をメモメモ。



まずはAccessから、csv形式でエクスポート・・・と思ったら、引数エラーとか言われてエクスポートできず・・・。とりあえずインポートしたいデータを表示させて、コピー&ペーストでテキストエディタに貼り付けて、タグをカンマに変換してcsv変換。

次に、SQL*Loaderで使うコントロールファイルの作成。以下のような感じで作ってみました。

LOAD DATA
INFILE [csvファイル名]
APPEND
INTO TABLE [テーブル名]
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
TRAILING NULLCOLS
(
  --ここにカラム名を列挙
)

1行目は、コントロールファイルのお約束みたいなもの。
2行目は、インポートするデータが入ったcsvファイルのファイル名。
3行目は、テーブルにデータを追加するので「APPEND」。新規に作る場合は「INSERT」で、「REPLACE/TRUNCATE」はテーブルのデータを全て削除してからデータを追加。
4行目は、インポート先テーブル名。
5行目は、csvファイルのカラム区切り記号を指定。タブ区切りの場合は「TERMINATED BY X'09'」。
6行目は、csvファイルのカラムデータを囲む文字の指定。上記の場合はダブルクォーテーションで囲っています、という意味。
7行目は、csvファイルのカラムデータが空の場合、NULLに置き換えます、という指定。
8行目以降のカッコの中に、インポート先テーブルのカラムを記述する。

コントロールファイルの作成が終わったら、後はコマンドを叩くだけ。

% sqlldr [DBユーザー名]/[DBユーザーパスワード]@[DB名] control=コントロールファイル名

実行後は、カレントディレクトリにlogファイルと、場合によってbadファイルができあがるので、必要に応じて確認する。

下手にAccessでテーブルをリンクさせて・・・なんてやるより、SQL*Loaderを使ってインポートした方が楽で早いかも。

[Java] ORA-01861エラー

ネイティブクエリを使ってOracleにアクセスしていたところ、開発環境では正常に動いていたのに、本番環境(サーバ機)で動かしたらORA-01861エラーが発生。

エラーメッセージによると、比較しようとしている型がマッチしていないとのこと。開発環境と本番環境でSQLは全く一緒なのに、なんでこんなエラーが出るんだろう。試しにSQL Plusで全く同じSQLを叩いてみても、エラーなく結果が表示されるのに。

ということで、DBのテーブルとSQLをにらめっこさせてみたところ、なんとなく引っかかったのが以下の部分。

where update_date < '2008-04-01'

update_dateはdate型だけど、'2008-04-01'って、この書き方だとstring型だから、date型とstring型の比較はできないよ!って言われているような雰囲気。

そこで、以下のように修正してみる。

where update_date < TO_DATE('2008-04-01','yyyy-mm-dd')

すると、エラーも消えて問題なく通るように。

Oracleは開発環境も本番環境も同じものを見ているし、違うのはglassfishのバージョンとJavaのバージョンくらい。ということで、開発環境に入っているglassfishかJavaのバージョン(本番環境よりやや新しいバージョン)では、暗黙の型変換をしてくれていた模様。

JPQLではこの辺の型変換をやってくれるので気にしていませんでしたが、ネイティブクエリでは全て自分で面倒を見ないといけないので、比較するときの型はきちんと合わせるべきでした。

絶対また同じミスをやりそうなので、忘れないうちにメモメモ(笑)

[Java/JPA] ネイティブクエリ Part.2

前にネイティブクエリの使い方を記事にしたとき、マッピングしなければ普通にオブジェクト型で取れる、と書いたものの、実はそんなに容易いものではありませんでした・・・。

プライマリキーが変動したり、プライマリキーにしないといけないカラムにnullが入っている可能性があるため、マッピングする方法が使えない!・・・という事態にぶつかってしまったため、オブジェクト型で取る方法を試してみたところ、どうやらtoplinkの仕様ではオブジェクト型ではなく、Vector型に値をセットしてくるとのこと。

Vector型?なにそれ?

調べてみたら、Listを継承していて、ArrayListと兄弟のような型らしい。

だったら簡単じゃん、と思って、以下のようにしてみました。実際に同じコードを作ったわけではなく、以下はサンプルということで。さらに言うと、try/catchやクラスなどを省略しています。

Vector<Object[]> result = null;
Query q = this.em.createNativeQuery("SELECT a, b, c FROM table_name");
result = (Vector<Object[]>) q.getResultList();
for (Object[] obj : result) {
    this.valueA.add((String) obj[0]);
    this.valueB.add((Integer) obj[1]);
    this.valueC.add((String) obj[2]);
}

デバッグモードで見ていくと確かに値は取れているものの、for文でエラーが出る。Vector型からObject型にキャストはできません、と。

Vector.toArray()がObject[]型で値を返すので、Object[] obj = result.toArray()を試してみても、なぜかobjはVector型だからObjectにキャストできないと怒られる。

デバッグモードで値を見ると、確かにVector<E>と出ている。なんだこれ?

じゃあ、Vectorの中もVectorなら、これならどうだ!と試してみたのが以下のやり方。

Vector<Vector<Object[]>> result = null;
Query q = this.em.createNativeQuery("SELECT a, b, c FROM table_name");
result = (Vector<Vector<Object[]>>) q.getResultList();
for (Vector<Object[]> objVector : result) {
    Object[] obj = objVector.toArray();
    this.valueA.add((String) obj[0]);
    this.valueB.add((Integer) obj[1]);
    this.valueC.add((String) obj[2]);
}

ふつーに動いた。

これが合ってるのか間違ってるのかはわからないけど、結果が正しいから間違ってはいないのかな。

とりあえず動かすことができたので、備忘録としてメモメモ。

これ間違ってるよ!とか、わかってないなぁ…こうなんだよ!なんてご意見があれば、どしどし募集します!いまだにVectorが良くわからないので教えてください!(苦笑)

あ、ちなみに。

この方法でDBからデータを取得すると、文字列カラムはString、数値カラムはBigDecimalとして受け取ってあげればいいようです。

[Java/JPA] ネイティブクエリ

SQLではできるけど、JPQLではどうしても実現できない条件があり、ネイティブクエリを使ってSQLを直接記述する方法を勉強したので、備忘録ということで。

まずはDBアクセスクラスにクエリを記述。

@Stateless
public class DbNativeQuery
       implements Serializable, IDbNativeQuery {

    private static final long serialVersionUID = 123456789L;

    @PersistenceContext(unitName = UnitName")
    private EntityManager em;

    public final List < DbList > outputList() {
        String sql = "SELECT id AS ID, name AS NAME, age AS AGE "
                   + "FROM table";
        List < DbList > list = null;
        try {
            Query query = em.createNativeQuery(sql, "DbList");
            query.setHint(TopLinkQueryHints.REFRESH, HintValues.TRUE);
            list = (List < DbList >) query.getResultList();
        } catch (Exception e) {
            System.out.println("Exception! [" + e.getMessage() + "]");
        }
        return list;
    }
}


続いて、エンティティクラス。

@SqlResultSetMapping(name = "DbList", entities = {
    @EntityResult(entityClass = DbList.class, fields = {
    @FieldResult(name = "ID",   column = "ID"),
    @FieldResult(name = "NAME", column = "NAME"),
    @FieldResult(name = "AGE",  column = "AGE")
    })
})
@Entity
public class DbList implements Serializable {
    private static final long serialVersionUID = 987654321L;

    @Id
    @Column(name = "ID")
    private String id;
    @Column(name = "NAME")
    private String name;
    @Column(name = "AGE")
    private String age;

    public DbList() {
    }

    public DbList(final String argId,
                  final String argName,
                  final String argAge) {
        this.id   = argId;
        this.name = argName;
        this.age  = argAge;
    }

    以下、必要に応じてgetterやsetterなど
}


上記のクエリならJPQLでも取れますが、まあごくごく簡単な条件でのネイティブクエリの使い方ということで。

ちなみに、マッピングしないのであればもっと簡単に書くことができますが、その辺は省略ということで。普通にオブジェクト型の配列で取れますし。

[SQL] レコード / テーブル更新

すぐ忘れるのでメモ!
Oracle での方法だけど、PostgreSQL や MySQL でもこのまま使えるはず。

条件に一致するレコードを更新
UPDATE table_name
   SET col1 = '01'
 WHERE col1 = '00';

テーブルのプライマリキーを変更
※PostgreSQLは、プライマリキーを1つしか設定できないらしい。
ALTER TABLE table_name DROP PRIMARY KEY;
ALTER TABLE table_name ADD PRIMARY KEY ( col1, col2 );

Linux で DLNA サーバ

以前、Windows マシンに TVersity を入れて DLNA サーバを立ててみましたが、普段は電源を落としてしまう PC だということと、せっかく Fedora8 を入れたサーバを動かしているということもあり、このサーバに DLNA サーバを立ててみました。

Linux 用 DLNA サーバはいくつかあるようですが、 PS3 で動作実績のある Mediatomb というものを選択。まずは、Mediatomb をダウンロード。

http://mediatomb.cc/pages/download


ん?ここへ行ってみると、どうやら Fedora8 は、yum でインストールできるらしい。ということでさっそく。
# yum install mediatomb

必要なライブラリなども一緒にインストールしてくれるので楽なものです。

さて、インストールが終わったら、設定ファイルの編集。といっても一箇所だけ。

/etc/mediatomb.conf を開いて、MT_INTERFACE の値を実際に使っている NIC に変更。
MT_INTERFACE="NOT_SET" → MT_INTERFACE="eth0"

そして、起動させればOK。
# service mediatomb start
もしくは
# /etc/init.d/mediatomb start


Mediatomb では、ファイル管理に DB を使うらしく、MySQL を使うと快適らしいので、MySQL の設定も一緒に行う。

まずは MySQL を起動
# service mysqld start

rootのパスワードを作成
# /usr/bin/mysqladmin -u root password 'NEW-PASSWORD'

MySQLにログイン
# mysql -u root -p

ユーザーを確認
mysql> select host,user,password from mysql.user;
+------------+------+------------------+
| host       | user | password         |
+------------+------+------------------+
| localhost  | root | **************** |
| fedora     | root |                  |
| 127.0.0.1  | root |                  |
+------------+------+------------------+

パスワードがない root は危険なので、パスワードを設定
mysql> set password for root@'fedora'=password('NEW-PASSWORD');
mysql> set password for root@'127.0.0.1'=password('NEW-PASSWORD');

データベースを作成
mysql> create database DB_NAME;

一般ユーザー作成
mysql> grant select,insert,delete,update,create,drop,file,alter,index on *.* to DB_USER identified by 'PASSWORD';
mysql> flush privileges;

以上で MySQL の設定は OK。続いて Mediatomb のもうひとつの設定ファイルを開いて、環境に合わせて書き換え。

# vi /etc/mediatomb/config.xml

以下の部分を書き換え
<storage driver="sqlite3">
  <database-file>mediatomb.db</database-file>
</storage>

            ↓

<storage driver="mysql">
  <database-file>mediatomb.db</database-file>
  <host>localhost</host>
  <username>DB_USER</username>
  <password>DB_USER's PASSWORD</password>
  <database>DB_NAME</database>
  <port>3306</port>
</storage>
<protocolInfo extend="yes"/>


これで設定は完了。念のため Mediatomb を再起動させたら、次はムービーや音楽ファイルの置き場を指定します。

ブラウザから、サーバの50500ポートにアクセスします。

例:http://192.168.10.200:50500/

こんな画面が表示されます。
クリックで別窓に拡大表示します

Filesystem をクリックして、動画や静止画、音楽ファイルなどが置いてあるフォルダを表示します。
クリックで別窓に拡大表示します

フォルダごと登録するには右上の「+」をクリック、ファイル単位で登録する場合は、ファイル名の右にある「+」をクリックすればOK。また、フォルダを自動チェックさせたい場合は、右上の「+」の右にある、矢印が「+」の周りを回っているようなアイコンをクリックします。
クリックで別窓に拡大表示します

Scan Mode は Timed を選択し、Scan Interval を秒単位で(この場合1時間ごと)入力し、Set をクリックすれば設定は完了です。

Database をクリックし、Database → PC Directory → 公開設定したディレクトリ名 と辿って行けば、その中に公開設定した各種ファイルが確認できます。
クリックで別窓に拡大表示します


ここまで設定できれば、あとは PS3 を起動し、メディアサーバを検索してみれば、MediaTomb という名前のサーバが見つかり、その中には公開設定したファイルが見えるようになっているはずです。

設定次第では、DivX や FLV なども再生できるようなので、また時間のあるときにでも設定してみようと思います。
フォト
2017年5月
  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 31      

最近のトラックバック