kdrug-inventory-system/find_duplicate_issue.py
시골약사 ad9ac396e2 chore: 개발 파일 정리 및 구조화
- 개발/테스트 스크립트를 dev_scripts/ 폴더로 이동
- 스크린샷을 screenshots/ 폴더로 이동
- 백업 파일 보존 (.backup)
- 처방 관련 추가 스크립트 포함

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-18 04:44:48 +00:00

192 lines
6.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
JOIN으로 인한 중복 문제 찾기
"""
import sqlite3
def find_duplicate_issue():
conn = sqlite3.connect('database/kdrug.db')
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
print("=" * 80)
print("JOIN으로 인한 중복 문제 분석")
print("=" * 80)
print()
# 1. 효능 태그 JOIN 없이 계산
print("1. 효능 태그 JOIN 없이 계산")
print("-" * 60)
cursor.execute("""
SELECT
h.herb_item_id,
h.herb_name,
COALESCE(SUM(il.quantity_onhand * il.unit_price_per_g), 0) as total_value
FROM herb_items h
LEFT JOIN inventory_lots il ON h.herb_item_id = il.herb_item_id AND il.is_depleted = 0
GROUP BY h.herb_item_id, h.herb_name
HAVING total_value > 0
ORDER BY total_value DESC
LIMIT 5
""")
simple_results = cursor.fetchall()
simple_total = 0
for item in simple_results:
simple_total += item['total_value']
print(f" {item['herb_name']:15}{item['total_value']:10,.0f}")
# 전체 합계
cursor.execute("""
SELECT SUM(total_value) as grand_total
FROM (
SELECT
h.herb_item_id,
COALESCE(SUM(il.quantity_onhand * il.unit_price_per_g), 0) as total_value
FROM herb_items h
LEFT JOIN inventory_lots il ON h.herb_item_id = il.herb_item_id AND il.is_depleted = 0
GROUP BY h.herb_item_id
HAVING total_value > 0
)
""")
simple_grand_total = cursor.fetchone()['grand_total'] or 0
print(f"\n 총합: ₩{simple_grand_total:,.0f}")
# 2. 효능 태그 JOIN 포함 계산 (API와 동일)
print("\n2. 효능 태그 JOIN 포함 계산 (API 쿼리)")
print("-" * 60)
cursor.execute("""
SELECT
h.herb_item_id,
h.herb_name,
COALESCE(SUM(il.quantity_onhand * il.unit_price_per_g), 0) as total_value,
COUNT(*) as row_count
FROM herb_items h
LEFT JOIN inventory_lots il ON h.herb_item_id = il.herb_item_id AND il.is_depleted = 0
LEFT JOIN herb_products hp ON h.insurance_code = hp.product_code
LEFT JOIN herb_item_tags hit ON COALESCE(h.ingredient_code, hp.ingredient_code) = hit.ingredient_code
LEFT JOIN herb_efficacy_tags et ON hit.tag_id = et.tag_id
GROUP BY h.herb_item_id, h.herb_name
HAVING total_value > 0
ORDER BY total_value DESC
LIMIT 5
""")
api_results = cursor.fetchall()
for item in api_results:
print(f" {item['herb_name']:15}{item['total_value']:10,.0f} (행수: {item['row_count']})")
# 전체 합계 (API 방식)
cursor.execute("""
SELECT SUM(total_value) as grand_total
FROM (
SELECT
h.herb_item_id,
COALESCE(SUM(il.quantity_onhand * il.unit_price_per_g), 0) as total_value
FROM herb_items h
LEFT JOIN inventory_lots il ON h.herb_item_id = il.herb_item_id AND il.is_depleted = 0
LEFT JOIN herb_products hp ON h.insurance_code = hp.product_code
LEFT JOIN herb_item_tags hit ON COALESCE(h.ingredient_code, hp.ingredient_code) = hit.ingredient_code
LEFT JOIN herb_efficacy_tags et ON hit.tag_id = et.tag_id
GROUP BY h.herb_item_id
HAVING total_value > 0
)
""")
api_grand_total = cursor.fetchone()['grand_total'] or 0
print(f"\n 총합: ₩{api_grand_total:,.0f}")
# 3. 중복 원인 분석
print("\n3. 중복 원인 분석")
print("-" * 60)
print(f" ✅ 정상 계산: ₩{simple_grand_total:,.0f}")
print(f" ❌ API 계산: ₩{api_grand_total:,.0f}")
print(f" 차이: ₩{api_grand_total - simple_grand_total:,.0f}")
if api_grand_total > simple_grand_total:
ratio = api_grand_total / simple_grand_total if simple_grand_total > 0 else 0
print(f" 배율: {ratio:.2f}")
# 4. 효능 태그 중복 확인
print("\n4. 효능 태그로 인한 중복 확인")
print("-" * 60)
cursor.execute("""
SELECT
h.herb_name,
h.ingredient_code,
COUNT(DISTINCT hit.tag_id) as tag_count
FROM herb_items h
LEFT JOIN herb_products hp ON h.insurance_code = hp.product_code
LEFT JOIN herb_item_tags hit ON COALESCE(h.ingredient_code, hp.ingredient_code) = hit.ingredient_code
WHERE h.herb_item_id IN (
SELECT herb_item_id FROM inventory_lots
WHERE is_depleted = 0 AND quantity_onhand > 0
)
GROUP BY h.herb_item_id
HAVING tag_count > 1
ORDER BY tag_count DESC
LIMIT 5
""")
multi_tags = cursor.fetchall()
if multi_tags:
print(" 여러 효능 태그를 가진 약재:")
for herb in multi_tags:
print(f" - {herb['herb_name']}: {herb['tag_count']}개 태그")
# 5. 특정 약재 상세 분석 (휴먼감초)
print("\n5. 휴먼감초 상세 분석")
print("-" * 60)
# 정상 계산
cursor.execute("""
SELECT
il.lot_id,
il.quantity_onhand,
il.unit_price_per_g,
il.quantity_onhand * il.unit_price_per_g as value
FROM inventory_lots il
JOIN herb_items h ON il.herb_item_id = h.herb_item_id
WHERE h.herb_name = '휴먼감초' AND il.is_depleted = 0
""")
gamcho_lots = cursor.fetchall()
actual_total = sum(lot['value'] for lot in gamcho_lots)
print(f" 실제 LOT 수: {len(gamcho_lots)}")
for lot in gamcho_lots:
print(f" LOT {lot['lot_id']}: {lot['quantity_onhand']}g ×{lot['unit_price_per_g']} = ₩{lot['value']:,.0f}")
print(f" 실제 합계: ₩{actual_total:,.0f}")
# JOIN 포함 계산
cursor.execute("""
SELECT COUNT(*) as join_rows
FROM herb_items h
LEFT JOIN inventory_lots il ON h.herb_item_id = il.herb_item_id AND il.is_depleted = 0
LEFT JOIN herb_products hp ON h.insurance_code = hp.product_code
LEFT JOIN herb_item_tags hit ON COALESCE(h.ingredient_code, hp.ingredient_code) = hit.ingredient_code
LEFT JOIN herb_efficacy_tags et ON hit.tag_id = et.tag_id
WHERE h.herb_name = '휴먼감초' AND il.lot_id IS NOT NULL
""")
join_rows = cursor.fetchone()['join_rows']
print(f"\n JOIN 후 행 수: {join_rows}")
if join_rows > len(gamcho_lots):
print(f" ⚠️ 중복 발생! {join_rows / len(gamcho_lots):.1f}배로 뻥튀기됨")
conn.close()
if __name__ == "__main__":
find_duplicate_issue()