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.
?print-pdf
' Created for
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 |
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( |
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( , NUMERIC( |
Varies; see following discussion | Depends on M and D | Depends on M and D |
BIT( |
approximately (M +7)/8 bytes |
0 | 2^M - 1 |
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;
first_name CHAR(4),
short_notes VARCHAR(50000),
Example
smoker ENUM('yes','no')
'YYYY-MM-DD'
or 'YY-MM-DD'
, like '2016-03-28' or '16-03-28''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'
SELECT [select_option]
{select_expression}
[
FROM table_reference
JOIN
ON
WHERE
GROUP BY
HAVING
ORDER BY
LIMIT
INTO
]
SELECT first_name, order_date
FROM customers.customers as customers, orders
WHERE customers.id=orders.customer_id
customers.customer
INSERT INTO table_name [(column, ...)]
VALUES (value, ...)[, (...), ...];
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
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 FROM table_name
[WHERE where_condition]
[ORDER BY ...]
[LIMIT row_count]
DELETE FROM artist WHERE
artist_id BETWEEN 9 AND 13;
Query OK, 5 rows affected
UPDATE table_name
SET column1=value, column2=value2,...
[WHERE where_clause]
[ORDER BY ...]
[LIMIT row_count]
UPDATE artist
SET fname='Test', lname='Test'
WHERE artist_id >= 14;
Query OK, 2 rows affected
The syntax:
ALTER TABLE table_name ADD INDEX(column_name(index_length));
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.
The syntax:
CREATE INDEX column_name ON table_name (column_name(index_length));
CREATE TABLE artist (
fname VARCHAR(20) DEFAULT NULL,
lname VARCHAR(20) NOT NULL,
INDEX(lname(10))
);
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.
NOT NULL
", "UNIQUE
", "PRIMARY KEY
", "FOREIGN KEY
", "CHECK
", "DEFAULT
"
CREATE TABLE table_name(
column_name data_type(size) constraint_name,
...
);
Indicates that a column cannot store NULL value
CREATE TABLE book (
id SMALLINT(3) UNSIGNED NOT NULL,
...
);
Specifies a default value for a column
CREATE TABLE book (
pub_year MEDIUMINT(4) DEFAULT NULL,
...
);
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.
Self-learning section:
w3schools: SQL CHECK Constraint
CREATE TABLE book (
id SMALLINT(3) UNSIGNED NOT NULL 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)
);
# 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;
customers_orders
which will store foreign keys to customers(id)
and orders(id)
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
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
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]
DELETE FROM author WHERE lname='Vonnegut' and fname='Kurt';
SELECT author.fname, author.lname, book_name FROM book, author WHERE book.author_id=author.id;
# make sure you're in the venv
pip install mysql-connector-python
import mysql.connector
# Establish a connection to the MySQL server
db = mysql.connector.connect(
host="localhost",
user="test",
password="test1234",
database="test"
)
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()
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()
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()
SimpleUserManagment/
├── db
│ ├── config.py
│ ├── __init__.py
│ └── operations.py
└── main.py
mysql-connector-python
package installed:
pip install mysql-connector-python
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
);
# db_config.py
db_config = {
'user': 'yourusername',
'password': 'yourpassword',
'host': '127.0.0.1',
'database': 'testdb',
}
# 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")
# 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()