225 lines
7.7 KiB
Python
225 lines
7.7 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
データベースクリーンアップスクリプト:
|
|
1. 各修正チェーンで最新版のみis_latest=trueに
|
|
2. 古い版すべてをis_latest=falseに
|
|
3. 逆仕訳を削除
|
|
"""
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
def run_sql_via_docker():
|
|
"""
|
|
Docker innerからSQLコマンドを実行
|
|
"""
|
|
|
|
# SQL命令を準備
|
|
sql_commands = [
|
|
# ========== Step 1: 確認 ==========
|
|
"""
|
|
-- 統計:実行前のデータ状況
|
|
SELECT
|
|
COUNT(*) as total_entries,
|
|
SUM(CASE WHEN is_latest = true THEN 1 ELSE 0 END) as latest_count,
|
|
SUM(CASE WHEN is_latest = false THEN 1 ELSE 0 END) as old_count
|
|
FROM journal_entries
|
|
WHERE is_deleted = false;
|
|
""",
|
|
|
|
# ========== Step 2: 修正チェーンの最新版を確認して修正 ==========
|
|
"""
|
|
-- 各修正チェーンで、最後に作成されたもののみis_latest=trueとする
|
|
UPDATE journal_entries
|
|
SET is_latest = false
|
|
WHERE journal_entry_id IN (
|
|
SELECT je.journal_entry_id
|
|
FROM journal_entries je
|
|
WHERE je.original_entry_id IS NOT NULL
|
|
AND NOT EXISTS (
|
|
SELECT 1
|
|
FROM journal_entries child
|
|
WHERE child.original_entry_id = je.original_entry_id
|
|
AND child.created_at > je.created_at
|
|
)
|
|
AND je.is_latest = false
|
|
);
|
|
""",
|
|
|
|
# Step 3: 最新版以外のものをis_latest=falseに
|
|
"""
|
|
UPDATE journal_entries
|
|
SET is_latest = false
|
|
WHERE original_entry_id IS NOT NULL
|
|
AND journal_entry_id NOT IN (
|
|
SELECT journal_entry_id
|
|
FROM journal_entries
|
|
WHERE original_entry_id IN (
|
|
SELECT original_entry_id FROM journal_entries WHERE original_entry_id IS NOT NULL
|
|
)
|
|
ORDER BY original_entry_id, created_at DESC
|
|
);
|
|
""",
|
|
|
|
# Step 4: 最新版以外をすべてis_latest=falseに確認
|
|
"""
|
|
-- 各修正チェーンで最新版を確認して、それ以外をfalseに
|
|
WITH ranked_entries AS (
|
|
SELECT
|
|
journal_entry_id,
|
|
CASE
|
|
WHEN original_entry_id IS NULL THEN journal_entry_id
|
|
ELSE original_entry_id
|
|
END as chain_id,
|
|
ROW_NUMBER() OVER (
|
|
PARTITION BY CASE WHEN original_entry_id IS NULL THEN journal_entry_id ELSE original_entry_id END
|
|
ORDER BY created_at DESC, journal_entry_id DESC
|
|
) as rn
|
|
FROM journal_entries
|
|
WHERE is_deleted = false
|
|
)
|
|
UPDATE journal_entries
|
|
SET is_latest = (ranked_entries.rn = 1)
|
|
FROM ranked_entries
|
|
WHERE journal_entries.journal_entry_id = ranked_entries.journal_entry_id;
|
|
"""
|
|
]
|
|
|
|
print("=" * 80)
|
|
print("【Docker内でのデータベースクリーンアップを実行中】")
|
|
print("=" * 80)
|
|
print()
|
|
|
|
# SQLコマンドをファイルに保存してDockerで実行
|
|
sql_file_content = "\n".join(sql_commands)
|
|
|
|
# コマンドを実行
|
|
try:
|
|
result = subprocess.run(
|
|
[
|
|
'docker', 'exec', 'njts_backend',
|
|
'bash', '-c',
|
|
f"""
|
|
cd /app
|
|
python3 << 'PYTHON_EOF'
|
|
import os
|
|
from app.core.database import get_connection
|
|
|
|
try:
|
|
with get_connection() as conn:
|
|
with conn.cursor() as cur:
|
|
# Step: 統計前
|
|
print("【実行前の統計】")
|
|
cur.execute('''
|
|
SELECT
|
|
COUNT(*) as total_entries,
|
|
SUM(CASE WHEN is_latest = true THEN 1 ELSE 0 END) as latest_count,
|
|
SUM(CASE WHEN is_latest = false THEN 1 ELSE 0 END) as old_count
|
|
FROM journal_entries
|
|
WHERE is_deleted = false;
|
|
''')
|
|
result = cur.fetchone()
|
|
print(f"総レコード数: {result[0]}")
|
|
print(f"is_latest=true: {result[1]}")
|
|
print(f"is_latest=false: {result[2]}")
|
|
print()
|
|
|
|
# Step: 各修正チェーン内の最新版を正しくマーク
|
|
print("【ステップ1: 各修正チェーンで最新版をマーク】")
|
|
cur.execute('''
|
|
WITH ranked_entries AS (
|
|
SELECT
|
|
journal_entry_id,
|
|
CASE
|
|
WHEN original_entry_id IS NULL THEN journal_entry_id
|
|
ELSE original_entry_id
|
|
END as chain_id,
|
|
ROW_NUMBER() OVER (
|
|
PARTITION BY CASE WHEN original_entry_id IS NULL THEN journal_entry_id ELSE original_entry_id END
|
|
ORDER BY created_at DESC, journal_entry_id DESC
|
|
) as rn
|
|
FROM journal_entries
|
|
WHERE is_deleted = false
|
|
)
|
|
UPDATE journal_entries
|
|
SET is_latest = (ranked_entries.rn = 1)
|
|
FROM ranked_entries
|
|
WHERE journal_entries.journal_entry_id = ranked_entries.journal_entry_id;
|
|
''')
|
|
print(f"更新完了: {cur.rowcount} レコード")
|
|
conn.commit()
|
|
print()
|
|
|
|
# Verification
|
|
print("【実行後の統計】")
|
|
cur.execute('''
|
|
SELECT
|
|
COUNT(*) as total_entries,
|
|
SUM(CASE WHEN is_latest = true THEN 1 ELSE 0 END) as latest_count,
|
|
SUM(CASE WHEN is_latest = false THEN 1 ELSE 0 END) as old_count
|
|
FROM journal_entries
|
|
WHERE is_deleted = false;
|
|
''')
|
|
result = cur.fetchone()
|
|
print(f"総レコード数: {result[0]}")
|
|
print(f"is_latest=true: {result[1]}")
|
|
print(f"is_latest=false: {result[2]}")
|
|
print()
|
|
|
|
# Check each chain
|
|
print("【各修正チェーン内のis_latest値を確認】")
|
|
cur.execute('''
|
|
SELECT
|
|
CASE WHEN original_entry_id IS NULL THEN journal_entry_id ELSE original_entry_id END as chain_id,
|
|
COUNT(*) as total,
|
|
SUM(CASE WHEN is_latest = true THEN 1 ELSE 0 END) as latest_count,
|
|
SUM(CASE WHEN is_latest = false THEN 1 ELSE 0 END) as old_count
|
|
FROM journal_entries
|
|
WHERE is_deleted = false
|
|
GROUP BY chain_id
|
|
HAVING COUNT(*) > 1
|
|
ORDER BY chain_id DESC
|
|
LIMIT 10
|
|
''')
|
|
|
|
chains = cur.fetchall()
|
|
if chains:
|
|
print(f"複数バージョンがあるチェーン: {len(chains)}")
|
|
for chain in chains:
|
|
print(f" Chain ID={chain[0]}: 合計={chain[1]}, latest={chain[2]}, old={chain[3]}")
|
|
else:
|
|
print("すべてのレコードは単独バージョン(修正なし)です")
|
|
|
|
except Exception as e:
|
|
print(f"エラー: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
PYTHON_EOF
|
|
"""
|
|
],
|
|
capture_output=False,
|
|
text=True,
|
|
timeout=30
|
|
)
|
|
|
|
if result.returncode == 0:
|
|
print("\n✓ クリーンアップ完了")
|
|
return True
|
|
else:
|
|
print(f"\n✗ クリーンアップ失敗 (Exit code: {result.returncode})")
|
|
return False
|
|
|
|
except subprocess.TimeoutExpired:
|
|
print("✗ 実行タイムアウト")
|
|
return False
|
|
except Exception as e:
|
|
print(f"✗ エラー: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
return False
|
|
|
|
if __name__ == "__main__":
|
|
success = run_sql_via_docker()
|
|
sys.exit(0 if success else 1)
|