概要
SQLファイルから、特定のカラムのデータ以外のすべてを取得する必要性が生じましたので、Pythonプログラムで実装しました。
前提
例えば以下のようなSQLがあるとします。
INSERT INTO `fruit` (fruit_cd, fruit_name, price, quantity) VALUES
(1, 'バナナ', 200, 10) ,
(2, 'りんご', 500, 5) ,
(3, 'みかん', 300, 8) ,
(4, 'パイナップル', 1000, 3) ,
(5, 'ぶどう', 400, 6) ,
(6, 'いちご', 600, 4) ,
(7, 'メロン', 1500, 2) ,
(8, 'スイカ', 800, 7) ,
(9, 'キウイ', 300, 9) ,
(10, 'マンゴー', 1000, 3) ;
この時、上記のprice
以外の値を除いたすべてを行(レコード)を取得したい場合、どうすればいいか?
サンプルコードを紹介します。
サンプルコード
import re
def extract_values(file_path, pattern):
with open(file_path, 'r') as f:
content = f.read()
matches = re.findall(pattern, content)
return [(int(match[0]), match[1], int(match[2])) for match in matches]
path = 'sample_sql/sample.sql'
values = extract_values(path, r'\((\d+), \'(\w+)\', \d+, (\d+)\)')
print(values)
実行結果は以下の通りです。
[(1, 'バナナ', 10), (2, 'りんご', 5), (3, 'みかん', 8), (4, 'パイナップル', 3), (5, 'ぶどう', 6), (6, 'いちご', 4), (7, 'メロン', 2), (8, 'スイカ', 7), (9, 'キウイ', 9), (10, 'マンゴー', 3)]
price
以外が取得できていますね。
サンプルコード解説
①正規表現のキャプチャグループを利用して取得する
大事なポイントは正規表現の箇所です。
この正規表現パターンr'\((\d+), \'(\w+)\', \d+, (\d+)\)'
は、
数字(fruit_cd
)、文字列(fruit_name
)、数字(price
)、数字(quantity
)
の順にマッチします。
ここで、fruit_cd
、fruit_name
、quantity
のみをキャプチャグループにすることで、これらのみがre.findall
によって返される仕組みです。re.findall
関数は、2つの引数を取り、それぞれ「検索する正規表現パターン」と「検索対象の文字列」を指定、マッチしたものはすべてリストとして返す関数です。
正規表現における\d
は任意の数字(0-9までの一桁の数字)を表す文字クラスで、\w
は任意の単語文字(数字、小文字、大文字)を表す文字クラスです。
今回利用した正規表現パターンをより詳細に書くと以下の通りです。
-
\(
:括弧で始まる -
\d+
:1つ以上の数字。キャプチャグループ(()
で囲まれた部分)なので、マッチした部分は結果に含まれる -
,
:コンマとスペース -
\'(\w+)\'
:シングルクォートで囲まれた1つ以上の単語文字。これもキャプチャグループ -
,
:コンマとスペース -
\d+
:1つ以上の数字。()
で囲まないことによりマッチした部分は結果に含まれないようになります -
,
:コンマとスペース -
\d+
:1つ以上の数字。キャプチャグループ -
\)
:括弧で終わる
キャプチャグループについては以下で解説してくださっているのでご参考までに。
公式ドキュメントはこちら。
②数値のデータは数値のまま返すようにする
2点目は、return [(int(match[0]), match[1], int(match[2])) for match in matches]
です。
これがない場合、結果は以下のようになります。
[('1', 'バナナ', '10'), ('2', 'りんご', '5'), ('3', 'みかん', '8'), ('4', 'パイナップル', '3'), ('5', 'ぶどう', '6'), ('6', 'いちご', '4'), ('7', 'メロン', '2'), ('8', 'スイカ', '7'), ('9', 'キウイ', '9'), ('10', 'マンゴー', '3')]
元々数値だったデータが''
のついた文字列の形で出力されてしまいます。
そこで、各タプルの1つ目(fruit_cd
)と3つ目(quantity
)の要素を整数に変換し、2つ目の要素(fruit_name
)は文字列のまま返すようにしています。
文字列がなく全て数値の場合は以下のようにすればOKです。
return [int(match) for match in matches if match.isdigit()]
すべてのマッチを整数として返すようになります。