2012年6月26日火曜日

[mysql]load data intoでcsvファイルを読み込むときのこと

いや、CSVのフィールドってダブルクォーテーションで囲まれてるものですが
これはFIELDS ENCLOSED BY でフィールドの開始と終了の文字を指定できます。



LOAD DATA INFILE "/tmp/XXXXXXXX.CSV"
INTO TABLE XXXXXXXXXX
FIELDS
        TERMINATED BY ','
        ENCLOSED BY '"'
        ESCAPED BY '\\'
LINES
        STARTING BY ''
        TERMINATED BY '\n'
(column1,column2,column3...);


で、"XXXX""ZZZZZZ""XXXX" みたいなフィールドだと
XXXX"ZZZZZZ"XXXX として取り込んでくれます。

他にも、"""XXXXXXXX""" みたいなフィールドだと
"XXXXXXXX" として取り込んでくれます。


2012年6月21日木曜日

[mysql]load data infile の localオプションが曲者

■環境
fedora17
mysql5.1(mroonga)

MySQLには SQLモード という概念があり、これによって動作が変わる。
デフォルトでは http://d.hatena.ne.jp/sakaik/20100225/mysqlautochange のような動作。

で、数値型に文字列つっこもうとしたらエラーにしてほしい、なんてときは
http://dev.mysql.com/doc/refman/5.1/ja/server-sql-mode.html
で、TRADITIONAL モードにしてしまえばエラーになる。

これはODBCドライバとかJDBCドライバとかつかってると、クライアントによって動作が変わるかもしれないので、mysql コマンドでSQLを叩いて確認するのがいい。

で、LOAD DATA INFILE と LOAD DATA LOCAL INFILE では SQLモードを指定したとしても動作が異なる。
マジでハマった。

http://forums.mysql.com/read.php?79,378105,378105

sql-mode="strict_all_tables" has no effect when using Load Data Infile
上記リンク、LOAD DATA INFILE では sql_mode の strinct_all_tables が効果ないって困っている。


実際のSQLは示されていないけれど、これは LOAD DATA LOCAL INFILE の動作っぽい。


2個目にレスしている人は、


It's working for me. Try it in CAPS: 

set sql_mode='STRICT_ALL_TABLES'; 


うまく言ったよ、っと言っている。


この認識の際は「LOCAL」があるかないかだと思う。


実際に試してみたけれども、LOAD DATA LOCAL INFILE を実行しているセッションでは SET SESSION sql_mode='TRADITIONAL' を指定しても効果がなかった。

一応、そのセッション中で SELECT @@session.sql_mode; で STRICT_ALL_TABLES があることを確認した。

一方で、mysql コマンドから同じ INSERT 文を発行するとエラーになり、 show warnings; するとWARNING ではなく ERROR と、明確に差が出た。

で、これを解決するには下記。

http://bugs.mysql.com/bug.php?id=52084

LOAD DATA INFILE にすると sql_mode の設定が有効になって、型違いのデータをつっこもうとしたらエラーになってくれた。

LOCAL があるかないかですごい動作が変わるみたいです。。。


[mysql]load data infile

mysql の load data infile でハマった。
ハマる前から
http://d.hatena.ne.jp/treeapps/20110409/1302332142
な記事は見つけててわかってたのに…。

ハマったのはキー重複なデータを読み込んだ時にエラーになってほしいのに ignore されてしまう。
エラーになってほしいんだ。。。

で、上の記事で引用されているのは mysql4.1 のドキュメントで mysql5.1 じゃなかった。

そしてmysql5.1の日本語翻訳ドキュメントでは下記のように記述されていた。(2012-06-21現在)


http://dev.mysql.com/doc/refman/5.1/ja/load-data.html
もし IGNORE を指定すると、 固有キー値上の、既存行を複製するインプット行はスキップされます。もしどちらのオプションも指定しなければ、その動作は LOCAL キーワードが指定されたかどうかによって決まります。LOCAL を利用すると、複製キー値が見つかった時点でエラーが発生し、テキスト ファイルの残りは無視されます。LOCAL を使用しなければ、デフォルトの動作は IGNORE が指定された時と同じです。これは、サーバは操作の最中にファイルの送信を中止する事ができないからです。

でも、英語ドキュメントでは次のように。

http://dev.mysql.com/doc/refman/5.1/en/load-data.html
If you specify IGNORE, input rows that duplicate an existing row on a unique key value are skipped. If you do not specify either option, the behavior depends on whether the LOCAL keyword is specified. Without LOCAL, an error occurs when a duplicate key value is found, and the rest of the text file is ignored. With LOCAL, the default behavior is the same as if IGNORE is specified; this is because the server has no way to stop transmission of the file in the middle of the operation.
動作は英語ドキュメントと同じ(上のリンク先記事で記述されている内容)どおり、
LOCAL を指定しなければ キー重複でエラーにするよ、
LOCAL を指定すれば IGNORE にするよ、
ってことでした。


つまり LOCAL を指定すると REPLACE or IGNORE のいづれかになるということでした。


あー。

[mysql]トリガー

■トリガーの定義


CREATE TRIGGER trigger_name {BEFORE | AFTER} {INSERT | UPDATE | DELETE}
 ON tbl_name FOR EACH ROW trigger_stmt


■トリガー内で更新前、更新後(新規追加)のデータ
http://idocsq.net/page/157

このときNEW.カラム名は新たに追加・更新されるデータを、OLD.カラム名はそれまでカラムに保存されていたデータを表す。

■トリガーの確認

http://kozy.heteml.jp/pukiwiki/MySQL%2520%25A5%25C8%25A5%25EA%25A5%25AC/index.html#i09e95cf



SHOW TRIGGERS;


■トリガーの削除


DROP TRIGGER trigger01;


2012年6月20日水曜日

[bash]指定した名前のファイルパスを取得する

いろんなところからパクった寄せ集め。




[IntelliJ IDEA]MySQLのTimestamp


IDEAの Data Source で MySQL のテーブル見てたらエラー。

『Value '0000-00-00 00:00:00' can not be represented as java.sql.Timestamp : IDEA-84184』 http://youtrack.jetbrains.com/issue/IDEA-84184

Data Sources -> DataSourceProperties -> Advanced でプロパティ設定したら問題なく表示できた。

Key=Value
zeroDateTimeBehavior=convertToNull

2012年6月19日火曜日

[vim]ファイルエクスプローラーと複数ウィンドウ

vimで:Sex するとファイルエクスプローラーが開く。
操作は簡単で、HJKLがそれぞれ←↓↑→でEnterでディレクトリに入るかファイルを開く。
ファイルはvim内で分割ウィンドウとして開かれる。
Ctrl+W w でウィンドウをシーケンスに移動できるのでまずはこれで。

http://d.hatena.ne.jp/shim0mura/20111011/1318303833
←ここみてSexを知り
http://d.hatena.ne.jp/mickey24/20080815/1218797020
←ここで複数ウィンドウに分割したときのウィンドウ移動を知り
http://loumo.jp/wp/archive/20080701175525/
←Sexをちゃんと理解する


[python]csv形式の文字列を読み込む


csv.readerの第一引数iteratorはiteratorプロトコルを実装したオブジェクトを渡せばいいので、
ファイルじゃなくて文字列をcsv.readerに渡したいときはiteratorプロトコルを実装しているStringIOオブジェクトを渡してやればできるみたい。


区切り文字とかフィードの囲み文字とかも指定できる。





# -*- coding: utf-8 -*-
from StringIO import StringIO
import csv

__author__ = 'isann'

def main():
    text = """あ い う え お
1 2 3 4 5
"改行がある
文字列だよ" 2"""
    print(text)
    csv_reader = csv.reader(StringIO(text), delimiter='\t', quotechar='"')
    for row in csv_reader:
        print(row)
#        for elem in row:
#            print(elem)

if __name__ == "__main__":
    main()


[python]excelを読み込む

excelもxlsとxlsxでは扱いが異なる。
窓が生き残っていくならばxlsxのOpenXML形式になるか。

pythonでexcelの xls 拡張子の旧形式を扱うならば xlrd、xlsx 拡張子の新形式を扱うならば openpyxl になるっぽい。


サンプルです。

[python]csvのダブルクォーテーション フィールド内の改行コードをうまく読み込む

こんな感じで。

[python]win32clipboardで文字化け


これで。

textをencodeしてやれば文字列(str)になる。
pywin32-213.win32-py2.7.exe これインスコした。
win32clipboardはpywin32内の1モジュール。
http://sourceforge.jp/projects/sfnet_pywin32/downloads/pywin32/Build%20213/pywin32-213.win32-py2.7.exe/


import win32clipboard
import win32con



def get_text_clipboard():
    win32clipboard.OpenClipboard()
    text = win32clipboard.GetClipboardData(win32con.CF_UNICODETEXT)
    win32clipboard.CloseClipboard()
    return text


def set_text_clipboard(text):
    win32clipboard.OpenClipboard()
    win32clipboard.SetClipboardText(text)
    win32clipboard.CloseClipboard()



文字化けしたのでwin32conf.CF_TEXTからwin32con.CF_UNICODETEXTにした。