zenith-audit-system / sql /analytics.sql
vinny2005's picture
Initial commit of Zenith
2e5b4a1
Raw
History Blame Contribute Delete
3.63 kB
-- Forensic Analytical Queries for Zenith General Ledger
-- 1. DOUBLE-ENTRY INTEGRITY CHECK
-- Purpose: Ensures debits equal credits for every transaction ID. Any imbalance is an error.
SELECT
entry_id,
SUM(debit_amount) AS total_debit,
SUM(credit_amount) AS total_credit,
SUM(debit_amount) - SUM(credit_amount) AS discrepancy
FROM fact_journal_entries
GROUP BY entry_id
HAVING discrepancy <> 0;
-- 2. SEPARATION OF DUTIES (SoD) VIOLATION LOG
-- Purpose: Finds transactions posted and approved by the exact same user.
SELECT
fje.entry_id,
fje.transaction_date,
fje.posted_by,
fje.approved_by,
da.account_code,
da.account_name,
(fje.debit_amount + fje.credit_amount) AS transaction_amount,
fje.risk_score
FROM fact_journal_entries fje
JOIN dim_accounts da ON fje.account_key = da.account_key
WHERE fje.posted_by = fje.approved_by AND (fje.debit_amount > 0 OR fje.credit_amount > 0)
ORDER BY transaction_amount DESC;
-- 3. TRANSACTION SPLITTING PATTERN DETECTOR
-- Purpose: Identifies cases where a user posted multiple entries below the $5,000 threshold
-- to the same account on the same day, potentially trying to bypass approval limits.
WITH daily_postings AS (
SELECT
DATE(transaction_date) AS post_date,
posted_by,
account_key,
COUNT(DISTINCT entry_id) AS split_count,
SUM(debit_amount + credit_amount) AS total_daily_value,
GROUP_CONCAT(entry_id) AS split_entry_ids
FROM fact_journal_entries
WHERE (debit_amount + credit_amount) < 5000.0 -- Under threshold
AND (debit_amount + credit_amount) > 0
GROUP BY post_date, posted_by, account_key
)
SELECT
dp.post_date,
dp.posted_by,
da.account_code,
da.account_name,
dp.split_count,
dp.total_daily_value,
dp.split_entry_ids
FROM daily_postings dp
JOIN dim_accounts da ON dp.account_key = da.account_key
WHERE dp.split_count >= 3 -- 3 or more split entries in a single day
ORDER BY dp.total_daily_value DESC;
-- 4. OFF-HOURS TRANSACTION LOG (Rule 103 Compliance)
-- Purpose: Extract manual transactions posted outside core working hours (9 AM - 6 PM)
-- or on weekends, excluding system automated process accounts.
SELECT
fje.entry_id,
fje.transaction_date,
fje.posted_by,
du.clearance_level,
(fje.debit_amount + fje.credit_amount) AS transaction_amount,
da.account_name,
-- Extract hour from SQLite date string (Format: YYYY-MM-DD HH:MM:SS)
STRFTIME('%H', fje.transaction_date) AS posting_hour,
-- Extract day of week (0=Sunday, 6=Saturday in standard, SQLite has different values: 0-6 where 0 is Sunday)
STRFTIME('%w', fje.transaction_date) AS day_of_week
FROM fact_journal_entries fje
JOIN dim_users du ON fje.user_key = du.user_key
JOIN dim_accounts da ON fje.account_key = da.account_key
WHERE du.user_id <> 'usr_admin' -- Exclude automated processes
AND (
STRFTIME('%H', fje.transaction_date) < '09'
OR STRFTIME('%H', fje.transaction_date) >= '18'
OR STRFTIME('%w', fje.transaction_date) IN ('0', '6')
)
ORDER BY transaction_date DESC;
-- 5. EXECUTIVE AUDIT PROGRESS SUMMARY
-- Purpose: Overview of total transactions audited, pending reviews, and severity levels.
SELECT
COALESCE(fal.llm_determination, 'UNASSIGNED/NOT_ANOMALOUS') AS audit_determination,
COUNT(DISTINCT fje.entry_id) AS transaction_count,
SUM(fje.debit_amount + fje.credit_amount) / 2 AS total_value_affected,
AVG(fje.risk_score) AS average_risk_score
FROM fact_journal_entries fje
LEFT JOIN fact_audit_log fal ON fje.entry_id = fal.entry_id
GROUP BY audit_determination;