修正
This commit is contained in:
224
cleanup_database.py
Normal file
224
cleanup_database.py
Normal file
@@ -0,0 +1,224 @@
|
||||
#!/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)
|
||||
Reference in New Issue
Block a user