シェルスクリプトを使って、異なるデータベースからデータを取得し、それを結合してCSVファイルとして出力する方法です。
メインのデータにマスタ情報を結合して、CSVファイルとして出力したい状況があったんですが、結合したいデータが別のデータベースにあるため、単純なJOINでは対応できませんでした。(Dockerを使ってました)
そこで、結合したいデータを連想配列に格納しておくことで、後から検索できるようにしました。
テーブル定義
例として、employeesとdepartmentsという2つのテーブルを使用します。
それぞれのテーブルは以下のように定義されており、これらを結合してCSVファイルに出力したいなって想定です。
-
employeesテーブル(社員)employee_id employee_name department_id 1 山田 太郎 100 2 鈴木 次郎 200 3 田中 三郎 100 -
departmentsテーブル(部門)department_id department_name 100 人事 200 開発
シェルスクリプトでデータを取得・結合する手順
departmentsテーブルから部門データを取得し、employeesテーブルと結合してCSVファイルに出力するシェルスクリプトの手順です。
部門データを取得して連想配列に格納する
まず、departmentsテーブルから部門データを取得し、それを連想配列に格納します。
実行するSQLはSELECT department_id, department_name FROM departmentsです。
# 別DBの部門データを取得し、連想配列に格納する
declare -A department_map
while IFS=$'|' read -r department_id department_name; do
department_map["$department_id"]="$department_name"
done < <(docker compose exec -T db-container bash -c "psql -d database_b -A -t -c \\"SELECT department_id, department_name FROM departments\\"")
-
declare -A department_map:- 連想配列
department_mapを作成します。
- 連想配列
-
while IFS=$'|' read -r department_id department_name; do ... done:-
psqlコマンドで取得したデータをプロセス置換を使って直接読み込み、各行をdepartment_idとdepartment_nameに分割して処理します。 -
IFS=$'|'で区切り文字を指定できます。- PostgreSQLの場合、デフォルトの区切り文字はパイプ(
\)なので、IFS=$'|'としました。
- PostgreSQLの場合、デフォルトの区切り文字はパイプ(
-
-
department_map["$department_id"]="$department_name-
department_idをキーに、department_nameを保存しています。
-
連想配列の内容を確認
# 連想配列の内容を確認
echo "$(declare -p department_map)"
declare -pコマンドを使うことで、連想配列の内容を確認できます。
$(...)はコマンド置換で、かっこ内で実行されたコマンドの出力をキャプチャして文字列として扱います。この場合、declare -p department_mapの出力がキャプチャされて、最後にechoで出力されます。
このやり方知らなくて配列をループして一つずつechoで確認してました…
CSVファイルへの出力
employeesテーブルからデータを取得し、部門名を連想配列から取得してCSVファイルに書き出します。
実行するSQLはSELECT employee_id, employee_name, department_id FROM employeesです。
# CSVファイルに書き出し
{
# ヘッダー行を書き込み
echo "社員ID,社員名,部門ID,部門名"
# 社員データを取得し、部門名を連想配列から取得する
while IFS=$'|' read -r employee_id employee_name department_id; do
department_name="${department_map[$department_id]}"
echo "$employee_id,$employee_name,$department_id,$department_name"
done < <(docker compose exec -T db-container bash -c "psql -d database_a -A -t -c \\"SELECT employee_id, employee_name, department_id FROM employees\\"")
} > output.csv
-
echo "社員ID,社員名,部門ID,部門名"- CSVファイルのヘッダー行を書き込みます。
-
while IFS=$'|' read -r employee_id employee_name department_id; do ... done-
employeesテーブルから取得したデータを読み込み、連想配列からdepartment_nameを取得してCSVに書き出します。
-
-
department_name="${department_map[$department_id]}"-
department_idをキーとして、対応するdepartment_nameを連想配列から取得します。
-
スクリプト全体
スクリプトの全体は以下です。
#!/bin/bash
# 別DBの部門データを取得し、連想配列に格納する
declare -A department_map
while IFS=$'|' read -r department_id department_name; do
department_map["$department_id"]="$department_name"
done < <(docker-compose exec -T db-container bash -c "psql -d database_b -A -t -c \\"SELECT department_id, department_name FROM departments\\"")
# 連想配列の内容を確認
echo "$(declare -p department_map)"
# CSVファイルに書き出し
{
# ヘッダー行を書き込み
echo "社員ID,社員名,部門ID,部門名"
# 社員データを取得し、部門名を連想配列から取得する
while IFS=$'|' read -r employee_id employee_name department_id; do
department_name="${department_map[$department_id]}"
echo "$employee_id,$employee_name,$department_id,$department_name"
done < <(docker-compose exec -T db-container bash -c "psql -d database_a -A -t -c \\"SELECT employee_id, employee_name, department_id FROM employees\\"")
} > output.csv