MySQl - The Syntax

MySQL Storage Engines

MySQL Storage Engines

Overview

Storage engines are MySQL components that handle the SQL operations for different table types.
InnoDB is the default and most general-purpose storage engine, and Oracle recommends using it for tables except for specialized use cases.
In MySQL 8.0 the The CREATE TABLE statement created InnoDB tables by default.
Reference: storage-engines

            SHOW ENGINES
        
Engine Support Comment Transactions XA Savepoints
CSV YES Stores tables as CSV files NO NO NO
MRG_MyISAM YES Collection of identical MyISAM tables NO NO NO
SEQUENCE YES Generated tables filled with sequential values YES NO YES
MyISAM YES Non-transactional engine with good performance and small data footprint NO NO NO
MEMORY YES Hash based, stored in memory, useful for temporary tables NO NO NO
PERFORMANCE_SCHEMA YES Performance Schema NO NO NO
Aria YES Crash-safe tables with MyISAM heritage NO NO NO
InnoDB DEFAULT Supports transactions, row-level locking, foreign keys and encryption for tables YES YES YES

What is a Transaction?

A transaction is a logical unit of work that contains one or more SQL statements.
A transaction is an atomic unit.
The effects of all the SQL statements in a transaction can be either all committed (applied to the database) or all rolled back (undone from the database).
Reference: Introduction to Transactions

MySQL Data Types

MySQL Data Types

Overview

Understanding SQL data types is essential for several reasons:
  • Data Integrity: Choosing the correct data type ensures that the data stored in the database is accurate and consistent.
  • Performance Optimization: Proper data types can significantly improve query performance and overall database efficiency.
  • Storage Efficiency: Using appropriate data types helps in optimizing the storage space, reducing the amount of disk space required.
  • Data Validation: Data types provide a built-in validation mechanism, ensuring that only valid data is stored in the database.
  • Enhanced Querying: Understanding data types allows for more effective querying and manipulation of data.
MySQL supports SQL data types in several categories:
numeric types, date and time types, string (character and byte) types, spatial types, and the JSON data type.
Reference: Data Types

Numeric Data Types

Numeric Data Types

Numeric Data Types - Overview

Data Type Storage Required Minimum Value Maximum Value
TINYINT 1 byte -128 127
SMALLINT 2 bytes -32,768 32,767
MEDIUMINT 3 bytes -8,388,608 8,388,607
INT, INTEGER 4 bytes -2,147,483,648 2,147,483,647
BIGINT 8 bytes -9,223,372,036,854,775,808 9,223,372,036,854,775,807
FLOAT(p) 4 bytes if 0 <= p <= 24, 8 bytes if 25 <= p <= 53 -3.402823466E+38 3.402823466E+38
FLOAT 4 bytes -3.402823466E+38 3.402823466E+38
DOUBLE [PRECISION], REAL 8 bytes -1.7976931348623157E+308 1.7976931348623157E+308
DECIMAL(M,D), NUMERIC(M,D) Varies; see following discussion Depends on M and D Depends on M and D
BIT(M) approximately (M+7)/8 bytes 0 2^M - 1
Reference: Numeric Type Storage Requirements

Numeric Data Types - Examples


            CREATE DATABASE exampleDB;

            USE exampleDB;

            CREATE TABLE numeric_data_types_example (
                id INT AUTO_INCREMENT PRIMARY KEY,
                tinyint_column TINYINT,
                smallint_column SMALLINT,
                mediumint_column MEDIUMINT,
                int_column INT,
                bigint_column BIGINT,
                float_column FLOAT(7,4),
                double_column DOUBLE(15,8),
                decimal_column DECIMAL(10,2)
            );

            INSERT INTO numeric_data_types_example (
                tinyint_column,
                smallint_column,
                mediumint_column,
                int_column,
                bigint_column,
                float_column,
                double_column,
                decimal_column
            ) VALUES
                (127, 32767, 8388607, 2147483647, 9223372036854775807, 123.4567, 12345.67890123, 12345.67),
                (-128, -32768, -8388608, -2147483648, -9223372036854775808, -123.4567, -12345.67890123, -12345.67);

            SELECT * FROM numeric_data_types_example;
        

String Data Types

String Data Types

The CHAR Data Type

CHAR(M)
Can store fixed length strings.
The length is specified by M (defaults to 1).
The length can be any value from 0 to 255.
If a value entered is with length < M, then
the string is right padded with spaces.
Examples:

                    first_name CHAR(4),
                
Defines that first_name column will contains 4 character strings.

The VARCHAR Data Type

VARCHAR(M)
Can store variable length strings.
The length is specified by M - cannot by empty!
The length can be any value from 0 to 65,535.
VARCHAR values are stored as a 1-byte or 2-byte length prefix plus data. The length prefix indicates the number of bytes in the value. A column uses one length byte if values require no more than 255 bytes, two length bytes if values may require more than 255 bytes.
Examples:

                    short_notes VARCHAR(50000),
                
Defines that short_notes column will contains 50000 character strings.
The real size taken on disk will be 50000+2 bytes.

CHAR<->VARCHAR differences

BLOB and TEXT Data Types

BLOBBinary Large OBject
Stores large amounts of binary data, such as images, PDF or other types of files.
BLOB values are treated as binary strings - they have no character set!
TEXT
TEXT values are treated as character strings - they have a character set!
Reference: The BLOB and TEXT Types

ENUM

ENUM (from ENUMeration)
Defines a list of predefined values. Like: ('yes', 'no')
The value entered must be selected from that list (or it can be NULL)
The elements listed in the column specification are assigned index numbers, beginning with 1
Pros:
Compact data storage in situations where a column has a limited set of possible values.
The strings you specify as input values are automatically encoded as numbers
Reference: ENUM

Example


                smoker ENUM('yes','no')
            

Date and Time Types

Date and Time Types

The DATE Data Type

A date in YYYY-MM-DD format
Values range: between 1000-01-01 and 9999-12-31.
A date can be entered in several formats.
'YYYY-MM-DD' or 'YY-MM-DD', like '2016-03-28' or '16-03-28'
Any punctuation character may be used as the delimiter between date parts.
'2016/03/28' or '16/03/28'

The TIME Date Type

A time in HH:MM:SS format
Values range: between -838:59:59 UTC and 838:59:59 UTC.
Can represent a time, or time interval.
Can be inserted As a string in 'D HH:MM:SS' format. You can also use one of the following “relaxed” syntaxes: 'HH:MM:SS', 'HH:MM', 'D HH:MM', 'D HH', or 'SS'. Here D represents days and can have a value from 0 to 34.

The DATETIME Date Type

A date and time in YYYY-MM-DD HH:MM:SS format
Values range: between 1000-01-01 00:00:00 and 9999-12-31 23:59:59.
A DATETIME can be entered in several formats.
'YYYY-MM-DD HH:MM:SS' or 'YY-MM-DD HH:MM:SS', like '2016-03-28 09:54:10' or '16-03-28 09:54:10'
Any punctuation character may be used as the delimiter between date parts.
'2016/03/28 09.54.10' or '16/03/28 09.54.10'
The date and time parts can be separated by T rather than a space.
'2016-03-28 09:54:10' and '2016-03-28T09:54:10' are equivalent.

The TIMESTAMP Date Type

A date and time in YYYY-MM-DD HH:MM:SS format
Values range: between 1970-01-01 00:00:01 UTC and 2038-01-19 03:14:07 UTC.
MySQL converts TIMESTAMP values from the current time zone to UTC for storage, and back from UTC to the current time zone for retrieval
By default, the current time zone for each connection is the server time.
A TIMESTAMP value can be inserted in MYSQL the same way as a DATETIME value.

The DATETIME vs TIMESTAMP in MySQL

DATETIME
  • Format: YYYY-MM-DD HH:MM:SS
  • Range: from 1000-01-01 00:00:00 to 9999-12-31 23:59:59
  • Storage: 8 bytes
  • Time zone independent, stores the date and time exactly as inserted
  • Does not change with server time zone changes
  • Use case: Suitable for historical records or specific date and time values
TIMESTAMP
  • Format: YYYY-MM-DD HH:MM:SS
  • Range: from 1970-01-01 00:00:01 UTC to 2038-01-19 03:14:07 UTC
  • Storage: 4 bytes
  • Time zone aware, automatically converts to UTC for storage and back to the current time zone for retrieval
  • Changes with server or connection time zone changes
  • Supports automatic initialization and updating with CURRENT_TIMESTAMP
  • Use case: Suitable for log entries, tracking events, or any time zone sensitive data

Reference

Date and Time Data Types

Basic Data Manipulation Statements

SELECT and WHERE Clauses

Syntax


            SELECT [select_option]
            {select_expression}
            [
                FROM table_reference
                    JOIN
                    ON
                    WHERE
                    GROUP BY
                    HAVING
                    ORDER BY
                    LIMIT
                    INTO
            ]
        
Reference: SELECT Statement
WHERE clause requires at least one condition. If multiple conditions are needed, connect them using AND or OR logic operators.
Comparison Functions and Operators to use in WHERE Clause

Example


            SELECT first_name, order_date
                FROM customers.customers as customers, orders
                    WHERE customers.id=orders.customer_id
        
Note, that it is good practice to prefix table names with DB name, like: customers.customer

INSERT INTO table

The syntax


            INSERT INTO table_name [(column, ...)]
            VALUES (value, ...)[, (...), ...];
        
Column list is optional!
If not present, you should list in VALUES values for all columns, following the order in table definition.
You can insert more than 1 row at a time, by using a list of values arrays.

Examples

Without specifying columns


            INSERT INTO artist
            VALUES (0,'Robert', 'Smith');
        
            Query OK, 1 row affected
        

But:


            INSERT INTO artist
            VALUES ('Madonna');
        
            (1136, u"Column count doesn't match value count at row 1")
        

With explicit column specification


            INSERT INTO artist(lname)
            VALUES ('Piazzolla');
        
            Query OK, 1 row affected
        

Examples

Insert more than 1 row at a time


            INSERT INTO artist( lname, fname )
            VALUES ( 'Schnittke', 'Alfred' ),
                ( 'Pärt', 'Arvo' ),
                ( 'Shostakovich', 'Dmitri' );
        
            Query OK, 3 rows affected
        

Delete

The Syntax


            DELETE FROM table_name
            [WHERE where_condition]
            [ORDER BY ...]
            [LIMIT row_count]
        
The conditions in the optional WHERE clause identify which rows to delete. With no WHERE clause, all rows are deleted.
The LIMIT clause places a limit on the number of rows that can be deleted.
If the ORDER BY clause is specified, the rows are deleted in the order that is specified.

Examples


            DELETE FROM artist WHERE
                artist_id BETWEEN 9 AND 13;
        
            Query OK, 5 rows affected
        

Update

The Syntax


            UPDATE table_name
            SET column1=value, column2=value2,...
            [WHERE where_clause]
            [ORDER BY ...]
            [LIMIT row_count]
        
The WHERE clause, if given, specifies the conditions that identify which rows to update
With no WHERE clause, all rows are updated!
If the ORDER BY clause is specified, the rows are updated in the order that is specified.
The LIMIT clause places a limit on the number of rows that can be updated.

Examples


        UPDATE artist
        SET fname='Test', lname='Test'
        WHERE artist_id >= 14;
    
        Query OK, 2 rows affected
    

MySQL Indexes

Introduction

What and Why?

A database index is added to a table to speed up the search operation.
An index is used by the Database Search Engine to locate records very fast.
Indexes can be created for one or more columns.
Indexes are implemented as a type of tables, which keep index field and a pointer to each record into the actual table.
While adding index to a table will speed the SELECT queries, it will slow down the INSERT and UPDATE statement.

Types of indexes

A regular INDEX
PRIMARY KEY
FULLTEXT

Regular index

Add regular Index to a table

The syntax:


            ALTER TABLE table_name ADD INDEX(column_name(index_length));
        
The index_length could be specified to minimize the size of the index, and to optimize database access speed.
Consider adding Regular Index to columns which will be searched most often

Example

Let's have the artist table, defined as:


            mysql music_db_admin@localhost:music_db> desc artist;
            +---------+-------------+--------+-------+-----------+---------+
            | Field   | Type        | Null   | Key   |   Default | Extra   |
            |---------+-------------+--------+-------+-----------+---------|
            | fname   | varchar(20) | YES    |       |    <null> |         |
            | lname   | varchar(20) | NO     |       |    <null> |         |
            +---------+-------------+--------+-------+-----------+---------+
        

An index could be added as:


            ALTER TABLE artist ADD INDEX(lname(10));
        

Resulting in:


            mysql music_db_admin@localhost:music_db> desc artist;
            +---------+-------------+--------+-------+-----------+---------+
            | Field   | Type        | Null   | Key   |   Default | Extra   |
            |---------+-------------+--------+-------+-----------+---------|
            | fname   | varchar(20) | YES    |       |    <null> |         |
            | lname   | varchar(20) | NO     | MUL   |    <null> |         |
            +---------+-------------+--------+-------+-----------+---------+
        

The MUL key means that multiple occurrences of a value may occur within that column.

Using CREATE INDEX

The syntax:


            CREATE INDEX column_name ON table_name (column_name(index_length));
        
It is an alternative to adding an index with ALTER TABLE.
NB! They are equivalent, except that CREATE INDEX cannot be used to create a PRIMARY KEY

Adding indexes when creating tables

You should be aware that adding an index to a large table can take a very long time.
That's why is better to add Regular Index when creating the table!

            CREATE TABLE artist (
                fname VARCHAR(20) DEFAULT NULL,
                lname VARCHAR(20) NOT NULL,
                INDEX(lname(10))
            );
        

Primary key

Why using Primary Key?

Regular indexes do not impose the values to be unique!
The importance of having a key with a unique value for each row will come up when we start to combine data from different tables.

Create

By adding the PRIMARY KEY(column_name) at the end of CREATE TABLE.


            CREATE TABLE artist (
                id MEDIUMINT(4) NOT NULL AUTO_INCREMENT,
                fname VARCHAR(20) DEFAULT NULL,
                lname VARCHAR(20) NOT NULL,
                PRIMARY KEY(id)
            );
        

Resulting in:


            +---------+--------------+--------+-------+-----------+----------------+
            | Field   | Type         | Null   | Key   |   Default | Extra          |
            |---------+--------------+--------+-------+-----------+----------------|
            | id      | mediumint(4) | NO     | PRI   |    <null> | auto_increment |
            | fname   | varchar(20)  | YES    |       |    <null> |                |
            | lname   | varchar(20)  | NO     |       |    <null> |                |
            +---------+--------------+--------+-------+-----------+----------------+
        

NB! As PRIMARY KEY requires unique values, the NOT NULL and/or AUTO_INCREMENT attribute should be present.

The AUTO_INCREMENT attribute

The AUTO_INCREMENT attribute

The AUTO_INCREMENT attribute can be used to generate a unique identity for new rows.
A column defined with that attribute will set the value of its contents to that of the column entry in the previously inserted row, plus 1.

SQL Constraints and Foreign Key

SQL Constraints

Overview

MySQL constraints are used to define rules to allow or restrict what values can be stored in columns. The purpose of inducing constraints is to enforce the integrity of a database
Constraints are used to limit the type of data that can be inserted into a table
MySQL supports next constraints:, "NOT NULL", "UNIQUE", "PRIMARY KEY", "FOREIGN KEY", "CHECK", "DEFAULT"

                CREATE TABLE table_name(
                    column_name data_type(size) constraint_name,
                    ...
                );
            
Reference: MySQL Constraint @w3resource

NOT NULL

Indicates that a column cannot store NULL value


            CREATE TABLE book (
                id SMALLINT(3) UNSIGNED NOT NULL,
                ...
            );
        

DEFAULT

Specifies a default value for a column


            CREATE TABLE book (
                pub_year MEDIUMINT(4) DEFAULT NULL,
                ...
            );
    

UNIQUE

Ensures that each row for a column must have a unique value


            CREATE TABLE book (
                book_name VARCHAR(250) NOT NULL UNIQUE,
                ...
            );
        

Some vendors, MySQL as well, allows a UNIQUE column to be set with DEFAULT NULL values, as by definition a NULL value is not equal to a NULL value. Anyway, it is not recommended to have UNIQUE and DEFAULT NULL column.

CHECK

Self-learning section:

w3schools: SQL CHECK Constraint

PRIMARY KEY

Primary Key is a combination of a NOT NULL and UNIQUE.
Primary Key ensures that a column (or combination of two or more columns) have a unique identity which helps to find a particular record in a table more easily and quickly
We can add Primary Key within the column definition, like:

                CREATE TABLE book (
                    id SMALLINT(3) UNSIGNED NOT NULL PRIMARY KEY,
                    ...
                );
            
We can also add Primary Key within table definition, which allows us to set multiple columns as Primary Key:

                CREATE TABLE book (
                    id SMALLINT(3) UNSIGNED NOT NULL,
                    isbn SMALLINT(3) UNSIGNED NOT NULL,
                    author VARCHAR(10) NOT NULL,
                    PRIMARY KEY (id,isbn)
                );
            

FOREIGN KEY constraints

What is a FOREIGN KEY?

A FOREIGN KEY in one table points to a PRIMARY KEY in another table.
FOREIGN KEY relationships involve a parent table that holds the central data values, and a child table with identical values pointing back to its parent.
The FOREIGN KEY clause is specified in the child table. The parent and child tables must use the same storage engine. They must not be TEMPORARY tables.
Reference: FOREIGN KEY Constraints

            # define the Parent Table
            CREATE TABLE `customers` (
                `id` int NOT NULL AUTO_INCREMENT,
                `first_name` varchar(45) NOT NULL,
                `last_name` varchar(45) NOT NULL,
                `email` varchar(100) DEFAULT NULL,
                PRIMARY KEY (`id`)
            ) DEFAULT CHARSET=utf8;

        

            # define the Child Table
            CREATE TABLE `orders` (
                `id` int NOT NULL AUTO_INCREMENT,
                `customer_id` int NOT NULL,
                `order_date` datetime NOT NULL,
                PRIMARY KEY (`id`),
                FOREIGN KEY (`customer_id`) REFERENCES `customers` (`id`)
            ) DEFAULT CHARSET=utf8;

        

"One to Many" ER Diagram

customers_db_ERDiagram.png

With FOREIGN KEY we can implement "one to many" relationship between Parent and Child tables!
One customer can have many orders.
If we need "many to many" relation we could make third table: customers_orders which will store foreign keys to customers(id) and orders(id)

Example on child table insert

Note, that if we try to insert into orders the id of a customer, who does not exists, MySQL will through an error

            INSERT INTO orders (customer_id,order_date)
                VALUES (1, "2020-01-20 21:00:00");

            # Cannot add or update a child row: a foreign key constraint fails
        

FOREIGN KEY Constraint

Ensure the referential integrity of the data in one table to match values in another table

MySQL supports FOREIGN KEY Constraint only for InnoDB tables

FOREIGN KEY Constraint

The syntax


            [CONSTRAINT constraint_name]
            FOREIGN KEY [fk_name] (index_columns)
            REFERENCES tbl_name (index_columns)
            [ON DELETE action]
            [ON UPDATE action]
            [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE]
        
The CONSTRAINT clause, if given, supplies a name for the foreign key constraint. If you omit it, InnoDB creates a name.
FOREIGN KEY indicates the indexed columns in the child table that must match index values in the parent table. fk_name is the foreign key ID. If given, it is ignored unless InnoDB automatically creates an index for the foreign key; in that case, fk_name becomes the index name.
REFERENCES names the parent table and the index columns in that table to which the foreign key in the child table refers. The index_columns part of the REFERENCES clause must have the same number of columns as the index_columns that follows the FOREIGN KEY keywords.

FOREIGN KEY Constraint: ON DELETE

ON DELETE specifies what happens to the child table when parent table rows are deleted.
ON DELETE CASCADE causes matching child rows to be deleted when the corresponding parent row is deleted. In essence, the effect of the delete is cascaded from the parent to the child. This enables you to perform multiple-table deletes by deleting rows only from the parent table and letting InnoDB delete the corresponding rowsfrom the child table.
For MySQL InnoDB tables ON DELETE NO ACTION and ON DELETE RESTRICT are the same as omitting the ON DELETE clause,as the foreign key constraints are checked immediately.
ON DELETE SET NULL causes index columns in matching child rows to be set to NULL when the parent row is deleted. If you use this option, all the indexed child table columns named in the foreign key definition must be defined topermit NULL values

FOREIGN KEY Constraint: ON UPDATE

ON UPDATE enables you to specify what happens to the child table when parent table rows are updated.
If ON UPDATE clause is not present, the default behaviour is to reject any inserts or updates in the child table that result in foreign key values that don’t have any match in the parent table index, and to prevent updates to parent table index values to which child rows point.
The possible action values are the same as for ON DELETE and have similar effects.

FOREIGN KEY Constraint: Guidelines

You must create the parent table index explicitly before defining the foreign key relationship.
InnoDB automatically creates an index on foreign key columns (the referencing columns) in the child table if the CREATE TABLE statement does not include such an index.
The automatically created index will be a non unique index and will include only the foreign key columns.
You should define the index in the child table explicitly if you want it to be a PRIMARY KEY or UNIQUE index, or if it should include other columns in addition to those in the foreign key.
Corresponding columns in the parent and child indexes must have compatible types.
Corresponding character columns must be the same length.
Corresponding integer columns must have the same size and same range (signed or unsigned).
For string columns, you must index the entire column, not just a leading prefix of it.

FOREIGN KEY Constraint: Examples

Download books_db schema
Download books_db sample data
Now let's delete an author from the author table:

                DELETE FROM author WHERE lname='Vonnegut' and fname='Kurt';
            
And check what happens with the books in book table:

                SELECT author.fname, author.lname, book_name FROM book, author WHERE book.author_id=author.id;
            

MySQL and Python

MySQL and Python

Python DB-API

Python Database API is a set of standards recommended by a Special Interest Group for database module standardization
Standard Python distribution has in-built support for SQLite database connectivity by the sqlite3 module
Other RDBMS products (Oracle, PostgreSQL, MySQL,...) also have DB-API compliant drivers
A database driver is a software that allows an application (like Python program) to connect and interact with a database system

MySQL Connector/Python

Reference: MySQL Connector/Python Developer Guide
Note, that MySQL’s official documentation uses the term connector instead of driver.
Installation:

            # make sure you're in the venv
            pip install mysql-connector-python
        

MySQL Connector - Create connection


            import mysql.connector

            # Establish a connection to the MySQL server
            db = mysql.connector.connect(
                host="localhost",
                user="test",
                password="test1234",
                database="test"
            )
        

MySQL Connector - Create table


            import mysql.connector

            # Establish a connection to the MySQL server
            db = mysql.connector.connect(
                ...
            )

            # Create a cursor object to interact with the database
            cursor = db.cursor()

            # SQL query to create a 'students' table
            create_table_query = """
            CREATE TABLE students (
                student_id INT AUTO_INCREMENT PRIMARY KEY,
                student_name VARCHAR(50),
                student_age INT,
                student_grade TINYINT CHECK (student_grade >= 2 AND student_grade <= 6)
            )
            """

            # Execute the query to create the table
            cursor.execute(create_table_query)

            # Commit changes to the database
            db.commit()

            # Close the cursor and database connection
            cursor.close()
            db.close()
        

MySQL Connector - Insert


            import mysql.connector

            # Establish a connection to the MySQL server
            db = mysql.connector.connect(
                ...
            )

            # Create a cursor object to interact with the database
            cursor = db.cursor()

            # Data to be inserted into the table
            student_data = [
                ("Alice", 20, 4),
                ("Bob", 22, 2),
                ("Charlie", 21, 5),
                ("Diana", 23, 6)
            ]

            # SQL query to insert data into the 'students' table
            insert_query = """
            INSERT INTO students (student_name, student_age, student_grade)
            VALUES (%s, %s, %s)
            """

            # Execute the query to insert data
            cursor.executemany(insert_query, student_data)

            # Commit changes to the database
            db.commit()

            # Close connection
            db.close()
        
In the provided code, %s is a placeholder used in SQL queries to indicate where the values should be inserted. When cursor.executemany(insert_query, student_data) is executed, the placeholders %s are replaced with the actual values from student_data for each record to be inserted. This is part of the parameterized query execution, which helps prevent SQL injection attacks

MySQL Connector - Fetch rows


            import mysql.connector

            # Establish a connection to the MySQL server
            db = mysql.connector.connect(
                ...
            )

            # Create a cursor object to interact with the database
            cursor = db.cursor()


            ### Example: Fetching all rows
            cursor.execute("SELECT * FROM students")
            rows = cursor.fetchall()
            for row in rows:
                print(row)

            ### Example:  Fetch a single row
            cursor.execute("SELECT * FROM students")

            row1 = cursor.fetchone()
            row2 = cursor.fetchone()
            print(row1)
            print(row2)

            db.close()
        

Hands-on: SimpleUserManagment

Hands-on: SimpleUserManagment

Project Overview

Let's build a simple Python project (SimpleUserManagment) that demonstrates how to interact with a MySQL database using the mysql-connector-python library. This example will cover basic CRUD (Create, Read, Update, Delete) operations.
Let's start with project structure:

                SimpleUserManagment/
                ├── db
                │   ├── config.py
                │   ├── __init__.py
                │   └── operations.py
                └── main.py
            
Make sure you have mysql-connector-python package installed:

                pip install mysql-connector-python
            

Create the Database and Table

You need to have a MySQL server running and create a database and table for your project:

                CREATE DATABASE testdb;
                USE testdb;

                CREATE TABLE users (
                    id INT AUTO_INCREMENT PRIMARY KEY,
                    name VARCHAR(255) NOT NULL,
                    email VARCHAR(255) NOT NULL UNIQUE
                );

            

Configuration File

Create a db_config.py file to store your database configuration:

                # db_config.py

                db_config = {
                    'user': 'yourusername',
                    'password': 'yourpassword',
                    'host': '127.0.0.1',
                    'database': 'testdb',
                }

            

Create Database Operations Module (db/operations.py)

Create an operations.py file in the db directory for database operations:

                # db/operations.py

                import mysql.connector
                from mysql.connector import Error
                from .config import db_config

                class MySQLDB:
                    def __init__(self):
                        self.connection = self.create_connection()

                    def create_connection(self):
                        connection = None
                        try:
                            connection = mysql.connector.connect(**db_config)
                            if connection.is_connected():
                                print("Connected to MySQL database")
                        except Error as e:
                            print(f"Error: '{e}'")
                        return connection

                    def create_user(self, name, email):
                        cursor = self.connection.cursor()
                        query = "INSERT INTO users (name, email) VALUES (%s, %s)"
                        cursor.execute(query, (name, email))
                        self.connection.commit()
                        print("User created successfully")

                    def get_users(self):
                        cursor = self.connection.cursor()
                        query = "SELECT * FROM users"
                        cursor.execute(query)
                        users = cursor.fetchall()
                        for user in users:
                            print(user)

                    def update_user_email(self, user_id, new_email):
                        cursor = self.connection.cursor()
                        query = "UPDATE users SET email = %s WHERE id = %s"
                        cursor.execute(query, (new_email, user_id))
                        self.connection.commit()
                        print("User email updated successfully")

                    def delete_user(self, user_id):
                        cursor = self.connection.cursor()
                        query = "DELETE FROM users WHERE id = %s"
                        cursor.execute(query, (user_id,))
                        self.connection.commit()
                        print("User deleted successfully")

                    def close_connection(self):
                        if self.connection.is_connected():
                            self.connection.close()
                            print("MySQL connection is closed")


            

Create Main Python File (main.py)

Create a main.py file for the main logic of the project:

                # main.py

                from db.operations import MySQLDB

                def main():
                    db = MySQLDB()

                    # Create a user
                    db.create_user("Ivan Ivanov", "ivan.ivanov@example.com")

                    # Read users
                    print("Users:")
                    db.get_users()

                    # Update a user's email
                    user_id = int(input("Enter user ID to update: "))
                    db.update_user_email(user_id, "ivan.newemail@example.com")

                    # Read users again to see the update
                    print("Updated Users:")
                    db.get_users()

                    # Delete a user
                    user_id = int(input("Enter user ID to delete: "))
                    db.delete_user(user_id)

                    # Read users again to see the deletion
                    print("Users after deletion:")
                    db.get_users()

                    # Close the connection
                    db.close_connection()

                if __name__ == "__main__":
                    main()