Topic 21 — Deploy Financial Ratios BI Model to SQL Server
This topic documents the real deployment process used to move the Financial Ratios Analysis in BI training package from CSV files into SQL Server.
Production / Cybersecurity Warning
This exercise uses synthetic training data. Do not run database creation, table drops, truncates, bulk loads, or permission commands against production systems without formal authorization.
Before deploying any real financial or accounting model, validate backups, permissions, least-privilege access, change-control approval, sandbox testing, audit requirements, and organizational cybersecurity protocols.
Objective
Deploy the completed synthetic financial BI model into SQL Server, validate the loaded tables, fix CSV loading issues, create reporting views, and prepare the model for Power BI.
FinancialRatiosBI
18 tables loaded, 4 views created, financial ratio categories validated.
Business Scenario
The training package already created a complete set of CSV files using Python. The next step is to move those files into a relational database so the model can be queried, validated, reused, and connected to Power BI as a real SQL Server data source.
Step-by-Step Practice
Step 1 — Create the Database and Tables
We executed SQL_Create_Tables.sql in SQL Server Management Studio. This created FinancialRatiosBI and all base tables.
USE FinancialRatiosBI;
GO
SELECT
TABLE_SCHEMA,
TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
ORDER BY TABLE_NAME;
GOStep 2 — Copy CSV Files to a SQL-Friendly Folder
SQL Server could not read directly from the user Documents path because the service account is different from the interactive Windows user.
New-Item -ItemType Directory -Path "C:\SQLData" -Force
Copy-Item `
-Path "." `
-Destination "C:\SQLData\financial_ratios_bi_training" `
-Recurse `
-Force
icacls "C:\SQLData\financial_ratios_bi_training" /grant "Everyone:(OI)(CI)R" /TStep 3 — Test a Single BULK INSERT
The first test confirmed SQL Server could read the file, but basic comma parsing split fields that contained commas inside text.
USE FinancialRatiosBI;
GO
TRUNCATE TABLE dbo.Dim_Company;
GO
BULK INSERT dbo.Dim_Company
FROM 'C:\SQLData\financial_ratios_bi_training\Dim_Company.csv'
WITH (
FIRSTROW = 2,
FIELDTERMINATOR = ',',
ROWTERMINATOR = '0x0a',
TABLOCK,
CODEPAGE = '65001'
);
GO
SELECT * FROM dbo.Dim_Company;
GOStep 4 — Fix CSV Loading with FORMAT = CSV
FORMAT = 'CSV' and FIELDQUOTE = '"' fixed quoted text fields.
USE FinancialRatiosBI;
GO
TRUNCATE TABLE dbo.Dim_Company;
GO
BULK INSERT dbo.Dim_Company
FROM 'C:\SQLData\financial_ratios_bi_training\Dim_Company.csv'
WITH (
FORMAT = 'CSV',
FIRSTROW = 2,
FIELDQUOTE = '"',
ROWTERMINATOR = '0x0a',
TABLOCK,
CODEPAGE = '65001'
);
GO
SELECT * FROM dbo.Dim_Company;
GOStep 5 — Load All Tables
Most tables loaded successfully using the fixed CSV pattern.
USE FinancialRatiosBI;
GO
/* Load All CSV Files - Fixed Version */
TRUNCATE TABLE dbo.Data_Quality_Issues;
TRUNCATE TABLE dbo.Data_Quality_Issues_Detail;
TRUNCATE TABLE dbo.Fact_Balance_Sheet;
TRUNCATE TABLE dbo.Fact_Cash_Flow;
TRUNCATE TABLE dbo.Fact_Cash_Flow_Ratios;
TRUNCATE TABLE dbo.Fact_Debt_Ratios;
TRUNCATE TABLE dbo.Fact_Employees;
TRUNCATE TABLE dbo.Fact_Income_Statement;
TRUNCATE TABLE dbo.Fact_Investment_Valuation_Ratios;
TRUNCATE TABLE dbo.Fact_Liquidity_Ratios;
TRUNCATE TABLE dbo.Fact_Market_Data;
TRUNCATE TABLE dbo.Fact_Operating_Performance_Ratios;
TRUNCATE TABLE dbo.Fact_Profitability_Ratios;
TRUNCATE TABLE dbo.Fact_Trial_Balance;
TRUNCATE TABLE dbo.Mapping_Financial_Statements;
TRUNCATE TABLE dbo.Dim_Account;
TRUNCATE TABLE dbo.Dim_Company;
TRUNCATE TABLE dbo.Dim_Period;
GO
-- Use this BULK INSERT pattern for every CSV table.
BULK INSERT dbo.Dim_Company
FROM 'C:\SQLData\financial_ratios_bi_training\Dim_Company.csv'
WITH (FORMAT = 'CSV', FIRSTROW = 2, FIELDQUOTE = '"', ROWTERMINATOR = '0x0a', TABLOCK, CODEPAGE = '65001');
GO
-- Repeat same pattern for Dim_Period, Dim_Account, Mapping, all Fact tables, and DQ tables.
-- In the live execution, most tables loaded successfully with this pattern.Step 6 — Validate Row Counts
The row count query identified the few tables that still needed help.
USE FinancialRatiosBI;
GO
SELECT 'Dim_Company' AS TableName, COUNT(*) AS [RowCount] FROM dbo.Dim_Company
UNION ALL SELECT 'Dim_Period', COUNT(*) FROM dbo.Dim_Period
UNION ALL SELECT 'Dim_Account', COUNT(*) FROM dbo.Dim_Account
UNION ALL SELECT 'Mapping_Financial_Statements', COUNT(*) FROM dbo.Mapping_Financial_Statements
UNION ALL SELECT 'Fact_Trial_Balance', COUNT(*) FROM dbo.Fact_Trial_Balance
UNION ALL SELECT 'Fact_Income_Statement', COUNT(*) FROM dbo.Fact_Income_Statement
UNION ALL SELECT 'Fact_Balance_Sheet', COUNT(*) FROM dbo.Fact_Balance_Sheet
UNION ALL SELECT 'Fact_Cash_Flow', COUNT(*) FROM dbo.Fact_Cash_Flow
UNION ALL SELECT 'Fact_Market_Data', COUNT(*) FROM dbo.Fact_Market_Data
UNION ALL SELECT 'Fact_Employees', COUNT(*) FROM dbo.Fact_Employees
UNION ALL SELECT 'Fact_Liquidity_Ratios', COUNT(*) FROM dbo.Fact_Liquidity_Ratios
UNION ALL SELECT 'Fact_Profitability_Ratios', COUNT(*) FROM dbo.Fact_Profitability_Ratios
UNION ALL SELECT 'Fact_Debt_Ratios', COUNT(*) FROM dbo.Fact_Debt_Ratios
UNION ALL SELECT 'Fact_Operating_Performance_Ratios', COUNT(*) FROM dbo.Fact_Operating_Performance_Ratios
UNION ALL SELECT 'Fact_Cash_Flow_Ratios', COUNT(*) FROM dbo.Fact_Cash_Flow_Ratios
UNION ALL SELECT 'Fact_Investment_Valuation_Ratios', COUNT(*) FROM dbo.Fact_Investment_Valuation_Ratios
UNION ALL SELECT 'Data_Quality_Issues', COUNT(*) FROM dbo.Data_Quality_Issues
UNION ALL SELECT 'Data_Quality_Issues_Detail', COUNT(*) FROM dbo.Data_Quality_Issues_Detail;
GOStep 7 — Use Python + pyodbc for the Hard CSV Tables
Dim_Account and Fact_Profitability_Ratios were loaded with pandas and pyodbc.
py -m pip install pandas pyodbc
py load_failed_tables_to_sql.pyfrom pathlib import Path
import pandas as pd
import pyodbc
base_path = Path(r"C:\SQLData\financial_ratios_bi_training")
server = r"JCDCOMPUTER"
database = "FinancialRatiosBI"
connection_string = (
"DRIVER={ODBC Driver 17 for SQL Server};"
f"SERVER={server};"
f"DATABASE={database};"
"Trusted_Connection=yes;"
)
conn = pyodbc.connect(connection_string)
cursor = conn.cursor()
cursor.fast_executemany = True
tables = {
"Dim_Account": "Dim_Account.csv",
"Fact_Profitability_Ratios": "Fact_Profitability_Ratios.csv"
}
for table_name, file_name in tables.items():
file_path = base_path / file_name
print(f"Loading {file_name} into dbo.{table_name}...")
df = pd.read_csv(file_path, dtype=str).fillna("")
df.columns = [col.strip().replace(" ", "_").replace("/", "_").replace("-", "_") for col in df.columns]
cursor.execute(f"DELETE FROM dbo.{table_name};")
conn.commit()
columns = list(df.columns)
column_list = ", ".join(f"[{col}]" for col in columns)
placeholders = ", ".join("?" for _ in columns)
insert_sql = f"INSERT INTO dbo.{table_name} ({column_list}) VALUES ({placeholders})"
rows = [tuple(row) for row in df.itertuples(index=False, name=None)]
cursor.executemany(insert_sql, rows)
conn.commit()
print(f"{table_name}: {len(df)} rows loaded successfully.")
cursor.close()
conn.close()
print("Failed tables loaded successfully.")Step 8 — Confirm All Tables Loaded
USE FinancialRatiosBI;
GO
SELECT 'Dim_Company' AS TableName, COUNT(*) AS [RowCount] FROM dbo.Dim_Company
UNION ALL SELECT 'Dim_Period', COUNT(*) FROM dbo.Dim_Period
UNION ALL SELECT 'Dim_Account', COUNT(*) FROM dbo.Dim_Account
UNION ALL SELECT 'Mapping_Financial_Statements', COUNT(*) FROM dbo.Mapping_Financial_Statements
UNION ALL SELECT 'Fact_Trial_Balance', COUNT(*) FROM dbo.Fact_Trial_Balance
UNION ALL SELECT 'Fact_Income_Statement', COUNT(*) FROM dbo.Fact_Income_Statement
UNION ALL SELECT 'Fact_Balance_Sheet', COUNT(*) FROM dbo.Fact_Balance_Sheet
UNION ALL SELECT 'Fact_Cash_Flow', COUNT(*) FROM dbo.Fact_Cash_Flow
UNION ALL SELECT 'Fact_Market_Data', COUNT(*) FROM dbo.Fact_Market_Data
UNION ALL SELECT 'Fact_Employees', COUNT(*) FROM dbo.Fact_Employees
UNION ALL SELECT 'Fact_Liquidity_Ratios', COUNT(*) FROM dbo.Fact_Liquidity_Ratios
UNION ALL SELECT 'Fact_Profitability_Ratios', COUNT(*) FROM dbo.Fact_Profitability_Ratios
UNION ALL SELECT 'Fact_Debt_Ratios', COUNT(*) FROM dbo.Fact_Debt_Ratios
UNION ALL SELECT 'Fact_Operating_Performance_Ratios', COUNT(*) FROM dbo.Fact_Operating_Performance_Ratios
UNION ALL SELECT 'Fact_Cash_Flow_Ratios', COUNT(*) FROM dbo.Fact_Cash_Flow_Ratios
UNION ALL SELECT 'Fact_Investment_Valuation_Ratios', COUNT(*) FROM dbo.Fact_Investment_Valuation_Ratios
UNION ALL SELECT 'Data_Quality_Issues', COUNT(*) FROM dbo.Data_Quality_Issues
UNION ALL SELECT 'Data_Quality_Issues_Detail', COUNT(*) FROM dbo.Data_Quality_Issues_Detail;
GOStep 9 — Create SQL Reporting Views
SQL_Financial_Views.sql created the reporting views.
USE FinancialRatiosBI;
GO
SELECT TABLE_SCHEMA, TABLE_NAME
FROM INFORMATION_SCHEMA.VIEWS
ORDER BY TABLE_NAME;
GO
SELECT TOP 20 *
FROM dbo.vw_All_Financial_Ratios;
GO
SELECT RatioCategory, COUNT(*) AS [RowCount], COUNT(DISTINCT RatioName) AS DistinctRatios
FROM dbo.vw_All_Financial_Ratios
GROUP BY RatioCategory
ORDER BY RatioCategory;
GOFinal SQL Server Deployment Result
The SQL Server deployment was completed successfully. The database contains 18 loaded tables and 4 reporting views.
Final Loaded Tables
| Table Name | Row Count |
|---|---|
| Dim_Company | 5 |
| Dim_Period | 20 |
| Dim_Account | 32 |
| Mapping_Financial_Statements | 28 |
| Fact_Trial_Balance | 2,800 |
| Fact_Income_Statement | 1,500 |
| Fact_Balance_Sheet | 2,400 |
| Fact_Cash_Flow | 700 |
| Fact_Market_Data | 100 |
| Fact_Employees | 100 |
| Fact_Liquidity_Ratios | 800 |
| Fact_Profitability_Ratios | 1,100 |
| Fact_Debt_Ratios | 1,000 |
| Fact_Operating_Performance_Ratios | 900 |
| Fact_Cash_Flow_Ratios | 1,200 |
| Fact_Investment_Valuation_Ratios | 1,700 |
| Data_Quality_Issues | 11 |
| Data_Quality_Issues_Detail | 6,782 |
Created SQL Views
| View Name | Status |
|---|---|
| vw_All_Financial_Ratios | Created successfully |
| vw_Executive_Financial_Summary | Created successfully |
| vw_Financial_Health_Inputs | Created successfully |
| vw_Latest_Period_Ratios | Created successfully |
Validated Ratio Categories
| Ratio Category | Row Count | Distinct Ratios |
|---|---|---|
| Cash Flow | 1,200 | 12 |
| Debt | 1,000 | 10 |
| Investment Valuation | 1,700 | 17 |
| Liquidity | 800 | 8 |
| Operating Performance | 900 | 9 |
| Profitability | 1,100 | 11 |
Business Interpretation
This topic turns the course into a real database workflow. The model is no longer only a collection of CSV files. It is now a SQL Server financial mini data warehouse with tables, validated loads, reporting views, and Power BI readiness.
The key learning is that data deployment is not just a technical copy process. It requires permissions, path control, CSV parsing, type handling, validation, troubleshooting, and final business verification.
Final Result of Topic 21
Python scripts → CSV files → SQL Server tables → SQL reporting views → Power BI-ready modelNext step: Connect Power BI Desktop to SQL Server using database FinancialRatiosBI and import the SQL views.