diff --git a/10 Očkování chřipka.py b/10 Očkování chřipka.py new file mode 100644 index 0000000..7086ad2 --- /dev/null +++ b/10 Očkování chřipka.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from pathlib import Path +import time +import fdb +import pandas as pd +from openpyxl import load_workbook +from openpyxl.worksheet.table import Table, TableStyleInfo +from openpyxl.styles import Font, PatternFill, Alignment +from openpyxl.utils import get_column_letter + +# ================== Výstupní cesta ================== +BASE_DIR = Path(r"..") # uprav dle potřeby +timestamp = time.strftime("%Y-%m-%d %H-%M-%S") +xlsx_name = f"Pacienti očkování {timestamp}.xlsx" +xlsx_path = BASE_DIR / xlsx_name + +# ================== Připojení k DB ================== +con = fdb.connect( + host='192.168.1.4', + database=r'z:\\MEDICUS 3\\data\\medicus.FDB', + user='sysdba', + password='masterkey', + charset='WIN1250' +) + +# ================== SQL dotaz ================== +# Pozn.: CAST(ockzaz.datum AS DATE) pro přesné párování na lecd.datose (DATE). +sql = """ +SELECT + kar.rodcis AS "Rodné číslo", + kar.prijmeni AS "Příjmení", + kar.jmeno AS "Jméno", + ockzaz.datum AS "Datum očkování", + ockzaz.kodmz AS "Kód MZ", + ockzaz.poznamka AS "Šarže", + ockzaz.latka AS "Látka", + ockzaz.nazev AS "Název", + ockzaz.expire AS "Expirace", + + /* --- VŠECHNY KÓDY Z TABULKY LECD PRO TOHO PACIENTA A TENTÝŽ DEN --- */ + ( + SELECT LIST(l.kod, ', ') + FROM lecd l + WHERE l.rodcis = kar.rodcis + AND l.datose = CAST(ockzaz.datum AS DATE) + ) AS "LECD kódy (ten den)" + +FROM registr +JOIN kar ON registr.idpac = kar.idpac +JOIN ockzaz ON registr.idpac = ockzaz.idpac +WHERE + registr.datum_zruseni IS NULL + AND kar.vyrazen <> 'A' + AND kar.rodcis IS NOT NULL + AND idicp <> 0 + and nazev containing 'chřipka' + and EXTRACT(YEAR FROM ockzaz.datum)=2025 +ORDER BY ockzaz.datum DESC +""" + +# ================== Načtení do DataFrame ================== +df = pd.read_sql(sql, con) +con.close() + +# Textové sloupce jako string +for col in ["Kód MZ", "Šarže", "Rodné číslo", "Látka", "Název", "Příjmení", "Jméno", "LECD kódy (ten den)"]: + if col in df.columns: + df[col] = df[col].astype("string") + +# Převod dat na datetime +for dcol in ["Datum očkování", "Expirace"]: + if dcol in df.columns: + df[dcol] = pd.to_datetime(df[dcol], errors="coerce") + +# ================== Uložení do Excelu ================== +with pd.ExcelWriter(xlsx_path, engine="openpyxl") as writer: + df.to_excel(writer, index=False, sheet_name="Očkování") + +# ================== Formátování ================== +wb = load_workbook(xlsx_path) + +def autosize_columns(ws): + for col_idx in range(1, ws.max_column + 1): + col_letter = get_column_letter(col_idx) + max_len = 0 + for cell in ws[col_letter]: + val = "" if cell.value is None else str(cell.value) + if len(val) > max_len: + max_len = len(val) + ws.column_dimensions[col_letter].width = min(max(12, max_len + 2), 60) + +def style_table(ws, table_name: str): + max_row = ws.max_row + max_col = ws.max_column + if max_col == 0: + return + + # Hlavička vzhled + header_fill = PatternFill("solid", fgColor="D9E1F2") + for cell in ws[1]: + cell.font = Font(bold=True) + cell.fill = header_fill + cell.alignment = Alignment(vertical="center") + + # Freeze top row + ws.freeze_panes = "A2" + + # Tabulka jen pokud jsou data + if max_row < 2: + autosize_columns(ws) + return + + ref = f"A1:{get_column_letter(max_col)}{max_row}" + tbl = Table(displayName=table_name, ref=ref) + tbl.tableStyleInfo = TableStyleInfo( + name="TableStyleMedium9", showRowStripes=True, showColumnStripes=False + ) + ws.add_table(tbl) + autosize_columns(ws) + +def format_dates(ws, columns_names): + header = [c.value for c in ws[1]] + date_cols = [header.index(name) + 1 for name in columns_names if name in header] + for col_idx in date_cols: + for row in ws.iter_rows(min_row=2, min_col=col_idx, max_col=col_idx, max_row=ws.max_row): + row[0].number_format = "DD.MM.YYYY" + +ws_main = wb["Očkování"] +style_table(ws_main, "Ockovani") +format_dates(ws_main, ["Datum očkování", "Expirace"]) + +wb.save(xlsx_path) + +print(f"Hotovo. Uloženo do: {xlsx_path}") diff --git a/20 Medicus all tables.py b/20 Medicus all tables.py new file mode 100644 index 0000000..3978b6e --- /dev/null +++ b/20 Medicus all tables.py @@ -0,0 +1,71 @@ +import fdb + +con = fdb.connect( + host='192.168.1.4', + database=r'z:\MEDICUS 3\data\medicus.FDB', + user='sysdba', + password='masterkey', + charset='WIN1250' +) +cur = con.cursor() + +# Query all user tables and their columns +cur.execute(""" +SELECT + rf.rdb$relation_name AS table_name, + rf.rdb$field_name AS column_name, + f.rdb$field_type AS field_type, + f.rdb$field_sub_type AS field_subtype, + f.rdb$field_length AS field_length, + f.rdb$field_precision AS field_precision, + f.rdb$field_scale AS field_scale, + f.rdb$null_flag AS not_null +FROM rdb$relation_fields rf +JOIN rdb$fields f ON rf.rdb$field_source = f.rdb$field_name +JOIN rdb$relations r ON rf.rdb$relation_name = r.rdb$relation_name +WHERE r.rdb$system_flag = 0 -- only user tables +ORDER BY rf.rdb$relation_name, rf.rdb$field_position +""") + +# helper to translate Firebird numeric codes to SQL types +fb_types = { + 7: "SMALLINT", + 8: "INTEGER", + 10: "FLOAT", + 12: "DATE", + 13: "TIME", + 14: "CHAR", + 16: "BIGINT/NUMERIC", + 27: "DOUBLE", + 35: "TIMESTAMP", + 37: "VARCHAR", + 261:"BLOB" +} + +schema = {} +for row in cur.fetchall(): + table = row[0].strip() + column = row[1].strip() + ftype = fb_types.get(row[2], f"TYPE{row[2]}") + subtype = row[3] + length = row[4] + precision = row[5] + scale = row[6] + not_null = bool(row[7]) + + # Build human-readable type + if ftype in ("CHAR","VARCHAR"): + dtype = f"{ftype}({length})" + elif ftype == "BIGINT/NUMERIC" and precision: + dtype = f"NUMERIC({precision},{-scale})" + else: + dtype = ftype + + coldef = f"{column} {dtype}{' NOT NULL' if not_null else ''}" + schema.setdefault(table, []).append(coldef) + +# Pretty print +for t, cols in schema.items(): + print(f"\nTable: {t}") + for c in cols: + print(" ", c) diff --git a/21 Medicus find table with leky.py b/21 Medicus find table with leky.py new file mode 100644 index 0000000..d5a485a --- /dev/null +++ b/21 Medicus find table with leky.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import fdb + +CODE = "0255910" + +con = fdb.connect( + host='192.168.1.4', + database=r'z:\MEDICUS 3\data\medicus.FDB', + user='sysdba', + password='masterkey', + charset='WIN1250' +) +cur = con.cursor() + +# --- find every user-table column defined as CHAR(7) --- +cur.execute(""" +SELECT + TRIM(rf.rdb$relation_name) AS table_name, + TRIM(rf.rdb$field_name) AS column_name +FROM rdb$relation_fields rf +JOIN rdb$fields f + ON rf.rdb$field_source = f.rdb$field_name +JOIN rdb$relations r + ON rf.rdb$relation_name = r.rdb$relation_name +WHERE + r.rdb$system_flag = 0 -- only user tables + AND r.rdb$view_blr IS NULL -- exclude views + AND f.rdb$field_type = 14 -- CHAR + AND f.rdb$field_length = 7 -- exactly CHAR(7) +ORDER BY rf.rdb$relation_name, rf.rdb$field_position +""") + +columns = cur.fetchall() +matches = [] + +# --- check each CHAR(7) column for exact match --- +for table_name, column_name in columns: + sql_count = f''' + SELECT COUNT(*) + FROM "{table_name}" + WHERE "{column_name}" = ? + ''' + try: + cur.execute(sql_count, (CODE,)) + cnt = cur.fetchone()[0] + except Exception as e: + print(f"Skipped {table_name}.{column_name}: {e}") + continue + + if cnt > 0: + sql_sample = f''' + SELECT FIRST 5 "{column_name}" + FROM "{table_name}" + WHERE "{column_name}" = ? + ''' + cur.execute(sql_sample, (CODE,)) + samples = [s.strip() if s else "" for (s,) in cur.fetchall()] + matches.append((table_name, column_name, int(cnt), samples)) + +# --- report --- +if not matches: + print(f'No exact matches for "{CODE}" in any CHAR(7) column.') +else: + print(f'Exact matches for "{CODE}" in CHAR(7) columns:') + for t, c, cnt, samples in matches: + print(f' - {t}.{c}: {cnt} row(s)') + for s in samples: + print(f' sample: {s}') + +con.close()