feat(add-data): Add script for SQL schema initialization
Since we are working with an Azure SQL database, we need to fill the generated customer data in a fitting schema. The schema will be described in more detail in an updated README file later. The added script uses `pyodbc` to connect to the database and create the tables. This requires a connection string, which will not be checked out to this repo for security reasons and must be obtained separately. Additionally, a script `test_sql_connection.py` is added with this commit, which is a simple utility to test the `pyodbc` connection.
This commit is contained in:
111
data_preparation/init_sql_schema.py
Normal file
111
data_preparation/init_sql_schema.py
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
"""Script to create the SQL schema in Azure SQL Database."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
import pyodbc
|
||||||
|
|
||||||
|
schema_creation = """
|
||||||
|
CREATE TABLE Addresses (
|
||||||
|
ID INT PRIMARY KEY IDENTITY(1,1),
|
||||||
|
StreetName NVARCHAR(100),
|
||||||
|
HouseNumber NVARCHAR(10),
|
||||||
|
City NVARCHAR(50),
|
||||||
|
PostalCode NVARCHAR(10),
|
||||||
|
Longitude FLOAT,
|
||||||
|
Latitude FLOAT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE Meters (
|
||||||
|
ID INT PRIMARY KEY IDENTITY(1,1),
|
||||||
|
Signature NVARCHAR(11),
|
||||||
|
MeterType NVARCHAR(3),
|
||||||
|
AddressID INT,
|
||||||
|
FOREIGN KEY (AddressID) REFERENCES Addresses(ID)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE Customers (
|
||||||
|
ID INT PRIMARY KEY IDENTITY(1,1),
|
||||||
|
FirstName NVARCHAR(100),
|
||||||
|
LastName NVARCHAR(100),
|
||||||
|
GasMeterID INT,
|
||||||
|
EltMeterID INT,
|
||||||
|
FOREIGN KEY (GasMeterID) REFERENCES Meters(ID),
|
||||||
|
FOREIGN KEY (EltMeterID) REFERENCES Meters(ID)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE Readings (
|
||||||
|
ID INT PRIMARY KEY IDENTITY(1,1),
|
||||||
|
CustomerID INT,
|
||||||
|
MeterID INT,
|
||||||
|
ReadingDate DATE,
|
||||||
|
ReadingValue INT,
|
||||||
|
FOREIGN KEY (CustomerID) REFERENCES Customers(ID),
|
||||||
|
FOREIGN KEY (MeterID) REFERENCES Meters(ID)
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def create_tables(cursor: pyodbc.Cursor, schema: str) -> None:
|
||||||
|
"""Create database tables based on the provided schema.
|
||||||
|
|
||||||
|
This function takes a database schema as a string and executes each table
|
||||||
|
creation statement separately. It handles cases where tables already exist
|
||||||
|
and reports this information.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
cursor : pyodbc.Cursor
|
||||||
|
A pyodbc cursor object used to execute SQL commands.
|
||||||
|
schema : str
|
||||||
|
A string containing SQL statements for table creation, separated by
|
||||||
|
semicolons.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
None
|
||||||
|
This function doesn't return any value.
|
||||||
|
|
||||||
|
Raises
|
||||||
|
------
|
||||||
|
pyodbc.ProgrammingError
|
||||||
|
If there's an error in executing the SQL statements, other than
|
||||||
|
"table already exists".
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
- The function assumes the existence of a global 'conn' object for
|
||||||
|
committing changes to the database.
|
||||||
|
- It prints a message if a table already exists instead of raising an error.
|
||||||
|
"""
|
||||||
|
for table_creation in schema.split(";"):
|
||||||
|
if table_creation.strip():
|
||||||
|
try:
|
||||||
|
cursor.execute(table_creation)
|
||||||
|
conn.commit()
|
||||||
|
except pyodbc.ProgrammingError as e:
|
||||||
|
if "There is already an object named" in str(e):
|
||||||
|
print(f"Table already exists: {table_creation.split('(')[0].split()[-1]}")
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
# Connect to the database
|
||||||
|
connection_string = os.environ.get("AZURE_SQL_CONNECTION_STRING")
|
||||||
|
|
||||||
|
try:
|
||||||
|
conn = pyodbc.connect(connection_string)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
print("Connected to Azure SQL Database successfully!")
|
||||||
|
|
||||||
|
# Example query
|
||||||
|
create_tables(cursor, schema_creation)
|
||||||
|
|
||||||
|
except pyodbc.Error as e:
|
||||||
|
print(f"Error connecting to Azure SQL Database: {e}")
|
||||||
|
finally:
|
||||||
|
if "cursor" in locals():
|
||||||
|
cursor.close()
|
||||||
|
if "conn" in locals():
|
||||||
|
conn.close()
|
||||||
56
data_preparation/test_sql_connection.py
Normal file
56
data_preparation/test_sql_connection.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
"""Script to test connection to Azure SQL Database."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
import pyodbc
|
||||||
|
|
||||||
|
|
||||||
|
def test_connection() -> bool:
|
||||||
|
"""Test the connection to Azure SQL Database.
|
||||||
|
|
||||||
|
This function attempts to establish a connection to an Azure SQL Database
|
||||||
|
using a connection string stored in the environment variable
|
||||||
|
'AZURE_SQL_CONNECTION_STRING'. It executes a simple query to verify
|
||||||
|
the connection and prints the result of the connection attempt.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
bool
|
||||||
|
True if the connection was successful and closed properly,
|
||||||
|
False if there was an error connecting to the database.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
- The function requires the 'AZURE_SQL_CONNECTION_STRING' environment
|
||||||
|
variable to be set with a valid connection string.
|
||||||
|
- It uses pyodbc to establish the database connection.
|
||||||
|
- The function prints success or error messages to stdout.
|
||||||
|
- In case of a successful connection, it executes "SELECT @@version;"
|
||||||
|
as a test query.
|
||||||
|
- The function ensures that both the cursor and the connection are
|
||||||
|
closed after the operation, regardless of its success or failure.
|
||||||
|
"""
|
||||||
|
connection_string = os.environ.get("AZURE_SQL_CONNECTION_STRING")
|
||||||
|
try:
|
||||||
|
conn = pyodbc.connect(connection_string)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
print("Connected to Azure SQL Database successfully!")
|
||||||
|
|
||||||
|
# Example query
|
||||||
|
cursor.execute("SELECT @@version;")
|
||||||
|
|
||||||
|
except pyodbc.Error as e:
|
||||||
|
print(f"Error connecting to Azure SQL Database: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if "cursor" in locals():
|
||||||
|
cursor.close()
|
||||||
|
if "conn" in locals():
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_connection()
|
||||||
Reference in New Issue
Block a user