シェルスクリプトを使って、異なるデータベースからデータを取得し、それを結合して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