0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

シェルスクリプトで複数のDBからデータを取得・結合し、CSVファイルに出力する

Posted at

シェルスクリプトを使って、異なるデータベースからデータを取得し、それを結合してCSVファイルとして出力する方法です。

メインのデータにマスタ情報を結合して、CSVファイルとして出力したい状況があったんですが、結合したいデータが別のデータベースにあるため、単純なJOINでは対応できませんでした。(Dockerを使ってました)

そこで、結合したいデータを連想配列に格納しておくことで、後から検索できるようにしました。

テーブル定義

例として、employeesdepartmentsという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_iddepartment_nameに分割して処理します。
    • IFS=$'|'で区切り文字を指定できます。
      • PostgreSQLの場合、デフォルトの区切り文字はパイプ(\)なので、IFS=$'|'としました。
  • 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
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?