Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Cơ sở dữ liệu Python và MySQL:Giới thiệu thực tế

MySQL là một trong những hệ quản trị cơ sở dữ liệu (DBMS) phổ biến nhất trên thị trường hiện nay. Nó chỉ xếp thứ hai sau Oracle DBMS trong Bảng xếp hạng DB-Engines của năm nay. Vì hầu hết các ứng dụng phần mềm cần tương tác với dữ liệu ở một số dạng, các ngôn ngữ lập trình như Python cung cấp các công cụ để lưu trữ và truy cập các nguồn dữ liệu này.

Sử dụng các kỹ thuật được thảo luận trong hướng dẫn này, bạn sẽ có thể tích hợp cơ sở dữ liệu MySQL với ứng dụng Python một cách hiệu quả. Bạn sẽ phát triển một cơ sở dữ liệu MySQL nhỏ cho hệ thống xếp hạng phim và tìm hiểu cách truy vấn nó trực tiếp từ mã Python của bạn.

Đến cuối hướng dẫn này, bạn sẽ có thể:

  • Xác định các tính năng độc đáo của MySQL
  • Kết nối ứng dụng của bạn vào cơ sở dữ liệu MySQL
  • Truy vấn cơ sở dữ liệu để tìm nạp dữ liệu được yêu cầu
  • Xử lý các ngoại lệ xảy ra khi truy cập cơ sở dữ liệu
  • Sử dụng các phương pháp hay nhất trong khi xây dựng các ứng dụng cơ sở dữ liệu

Để tận dụng tối đa hướng dẫn này, bạn nên có kiến ​​thức làm việc về các khái niệm Python như for vòng lặp, chức năng, xử lý ngoại lệ và cài đặt các gói Python bằng pip . Bạn cũng nên có hiểu biết cơ bản về hệ quản trị cơ sở dữ liệu quan hệ và các truy vấn SQL như SELECT , DROP , CREATEJOIN .

Tải xuống miễn phí: Nhận một chương mẫu từ Thủ thuật Python:Cuốn sách chỉ cho bạn các phương pháp hay nhất của Python với các ví dụ đơn giản mà bạn có thể áp dụng ngay lập tức để viết mã + Pythonic đẹp hơn.


So sánh MySQL với các Cơ sở dữ liệu SQL khác

SQL là viết tắt của Structured Query Language và là một ngôn ngữ lập trình được sử dụng rộng rãi để quản lý cơ sở dữ liệu quan hệ. Bạn có thể đã nghe nói về các hương vị khác nhau của các DBMS dựa trên SQL. Những cái phổ biến nhất bao gồm MySQL, PostgreSQL, SQLite và SQL Server. Tất cả các cơ sở dữ liệu này đều tuân thủ các tiêu chuẩn SQL nhưng với các mức độ tuân thủ khác nhau.

nguồn mở kể từ khi ra đời vào năm 1995, MySQL nhanh chóng trở thành công ty dẫn đầu thị trường trong số các giải pháp SQL. MySQL cũng là một phần của hệ sinh thái Oracle. Mặc dù chức năng cốt lõi của nó là hoàn toàn miễn phí, nhưng cũng có một số tiện ích bổ sung trả phí. Hiện tại, MySQL được sử dụng bởi tất cả các công ty công nghệ lớn, bao gồm Google, LinkedIn, Uber, Netflix, Twitter và những công ty khác.

Ngoài một cộng đồng nguồn mở lớn để được hỗ trợ, có nhiều lý do khác cho sự thành công của MySQL:

  1. Dễ cài đặt: MySQL được thiết kế để thân thiện với người dùng. Việc thiết lập cơ sở dữ liệu MySQL và một số công cụ của bên thứ ba có sẵn rộng rãi, như phpMyAdmin, đơn giản hóa hơn nữa quá trình thiết lập. MySQL có sẵn cho tất cả các hệ điều hành chính, bao gồm Windows, macOS, Linux và Solaris.

  2. Tốc độ: MySQL nổi tiếng là một giải pháp cơ sở dữ liệu cực nhanh. Nó có diện tích tương đối nhỏ hơn và có khả năng mở rộng cực kỳ cao về lâu dài.

  3. Đặc quyền và bảo mật của người dùng: MySQL đi kèm với một tập lệnh cho phép bạn đặt mức độ bảo mật của mật khẩu, gán mật khẩu quản trị và thêm và xóa các đặc quyền của tài khoản người dùng. Tập lệnh này không làm phức tạp quy trình quản trị cho cổng quản lý người dùng lưu trữ web. Các DBMS khác, như PostgreSQL, sử dụng các tệp cấu hình phức tạp hơn để sử dụng.

Trong khi MySQL nổi tiếng về tốc độ và tính dễ sử dụng, bạn có thể nhận được nhiều tính năng nâng cao hơn với PostgreSQL. Ngoài ra, MySQL không hoàn toàn tuân thủ SQL và có một số giới hạn chức năng nhất định, chẳng hạn như không hỗ trợ cho FULL JOIN mệnh đề.

Bạn cũng có thể gặp một số vấn đề với việc đọc và ghi đồng thời trong MySQL. Nếu phần mềm của bạn có nhiều người dùng ghi dữ liệu vào nó cùng một lúc, thì PostgreSQL có thể là một lựa chọn phù hợp hơn.

Lưu ý: Để có so sánh sâu hơn về MySQL và PostgreSQL trong bối cảnh thế giới thực, hãy xem Tại sao Uber Engineering chuyển từ Postgres sang MySQL.

SQL Server cũng là một DBMS rất phổ biến và được biết đến với độ tin cậy, hiệu quả và bảo mật. Nó được các công ty ưa thích, đặc biệt là trong lĩnh vực ngân hàng, những người thường xuyên xử lý khối lượng công việc lưu lượng lớn. Đây là một giải pháp thương mại và là một trong những hệ thống tương thích nhất với các dịch vụ Windows.

Năm 2010, khi Oracle mua lại Sun Microsystems và MySQL, nhiều người đã lo lắng về tương lai của MySQL. Vào thời điểm đó, Oracle là đối thủ cạnh tranh lớn nhất của MySQL. Các nhà phát triển lo sợ rằng đây là một sự tiếp quản thù địch từ Oracle với mục đích phá hủy MySQL.

Một số nhà phát triển dẫn đầu bởi Michael Widenius, tác giả ban đầu của MySQL, đã tạo ra một nhánh của cơ sở mã MySQL và đặt nền tảng của MariaDB. Mục đích là để bảo mật quyền truy cập vào MySQL và giữ cho nó miễn phí vĩnh viễn.

Cho đến nay, MariaDB vẫn được cấp phép đầy đủ GPL, giữ nó hoàn toàn trong phạm vi công cộng. Mặt khác, một số tính năng của MySQL chỉ khả dụng với các giấy phép trả phí. Ngoài ra, MariaDB cung cấp một số tính năng cực kỳ hữu ích mà máy chủ MySQL không hỗ trợ, như SQL phân tán và lưu trữ dạng cột. Bạn có thể tìm thấy thêm sự khác biệt giữa MySQL và MariaDB được liệt kê trên trang web của MariaDB.

MySQL sử dụng cú pháp rất giống với SQL chuẩn. Tuy nhiên, có một số khác biệt đáng chú ý được đề cập trong tài liệu chính thức.



Cài đặt Máy chủ MySQL và Trình kết nối MySQL / Python

Bây giờ, để bắt đầu làm việc thông qua hướng dẫn này, bạn cần thiết lập hai thứ: máy chủ MySQL trình kết nối MySQL . Máy chủ MySQL sẽ cung cấp tất cả các dịch vụ cần thiết để xử lý cơ sở dữ liệu của bạn. Sau khi máy chủ khởi động và chạy, bạn có thể kết nối ứng dụng Python của mình với nó bằng MySQL Connector / Python.


Cài đặt MySQL Server

Tài liệu chính thức nêu chi tiết cách được khuyến nghị để tải xuống và cài đặt máy chủ MySQL. Bạn sẽ tìm thấy hướng dẫn cho tất cả các hệ điều hành phổ biến, bao gồm Windows, macOS, Solaris, Linux và nhiều hệ điều hành khác.

Đối với Windows, cách tốt nhất là tải xuống MySQL Installer và để nó quản lý toàn bộ quá trình. Trình quản lý cài đặt cũng giúp bạn định cấu hình cài đặt bảo mật của máy chủ MySQL. Trên trang Tài khoản và Vai trò, bạn cần nhập mật khẩu cho root (quản trị) tài khoản và cũng có thể tùy chọn thêm người dùng khác với các đặc quyền khác nhau:

Mặc dù bạn phải chỉ định thông tin đăng nhập cho tài khoản gốc trong quá trình thiết lập, nhưng bạn có thể sửa đổi các cài đặt này sau này.

Lưu ý: Hãy nhớ tên máy chủ, tên người dùng và mật khẩu vì chúng sẽ được yêu cầu để thiết lập kết nối với máy chủ MySQL sau này.

Mặc dù bạn chỉ cần máy chủ MySQL cho hướng dẫn này, bạn cũng có thể thiết lập các công cụ hữu ích khác như MySQL Workbench bằng cách sử dụng các trình cài đặt này. Nếu bạn không muốn cài đặt MySQL trực tiếp trong hệ điều hành của mình, thì việc triển khai MySQL trên Linux với Docker là một giải pháp thay thế thuận tiện.



Cài đặt trình kết nối MySQL / Python

Trình điều khiển cơ sở dữ liệu là một phần mềm cho phép ứng dụng kết nối và tương tác với hệ thống cơ sở dữ liệu. Các ngôn ngữ lập trình như Python cần một trình điều khiển đặc biệt trước khi chúng có thể nói chuyện với cơ sở dữ liệu từ một nhà cung cấp cụ thể.

Các trình điều khiển này thường được lấy dưới dạng mô-đun của bên thứ ba. API cơ sở dữ liệu Python (DB-API) xác định giao diện tiêu chuẩn mà tất cả các trình điều khiển cơ sở dữ liệu Python phải tuân thủ. Các chi tiết này được ghi lại trong PEP 249. Tất cả các trình điều khiển cơ sở dữ liệu Python, chẳng hạn như sqlite3 cho SQLite, psycopg cho PostgreSQL và MySQL Connector / Python cho MySQL, hãy tuân theo các quy tắc triển khai này.

Lưu ý: Tài liệu chính thức của MySQL sử dụng thuật ngữ trình kết nối thay vì trình điều khiển . Về mặt kỹ thuật, các trình kết nối chỉ được liên kết với việc kết nối với cơ sở dữ liệu, không tương tác với nó. Tuy nhiên, thuật ngữ này thường được sử dụng cho toàn bộ mô-đun truy cập cơ sở dữ liệu bao gồm trình kết nối người lái xe.

Để duy trì tính nhất quán với tài liệu, bạn sẽ thấy thuật ngữ trình kết nối bất cứ khi nào MySQL được đề cập.

Nhiều ngôn ngữ lập trình phổ biến có API cơ sở dữ liệu riêng của chúng. Ví dụ:Java có API kết nối cơ sở dữ liệu Java (JDBC). Nếu bạn cần kết nối một ứng dụng Java với cơ sở dữ liệu MySQL, thì bạn cần sử dụng trình kết nối MySQL JDBC theo sau API JDBC.

Tương tự, trong Python, bạn cần cài đặt trình kết nối Python MySQL để tương tác với cơ sở dữ liệu MySQL. Nhiều gói tuân theo các tiêu chuẩn DB-API, nhưng phổ biến nhất trong số đó là MySQL Connector / Python. Bạn có thể lấy nó bằng pip :

$ pip install mysql-connector-python

pip cài đặt trình kết nối dưới dạng mô-đun của bên thứ ba trong môi trường ảo hiện đang hoạt động. Bạn nên thiết lập một môi trường ảo riêng biệt cho dự án cùng với tất cả các thành phần phụ thuộc.

Để kiểm tra xem cài đặt có thành công hay không, hãy nhập lệnh sau trên thiết bị đầu cuối Python của bạn:

>>>
>>> import mysql.connector

Nếu đoạn mã trên thực thi không có lỗi thì mysql.connector đã được cài đặt và sẵn sàng sử dụng. Nếu bạn gặp bất kỳ lỗi nào, hãy đảm bảo rằng bạn đang ở trong đúng môi trường ảo và bạn đang sử dụng trình thông dịch Python phù hợp.

Đảm bảo rằng bạn đang cài đặt đúng mysql-connector-python gói, là một triển khai Python thuần túy. Hãy cẩn thận với các trình kết nối được đặt tên tương tự nhưng hiện đã bị giảm giá trị như mysql-connector .




Thiết lập kết nối với máy chủ MySQL

MySQL là một dựa trên máy chủ hệ quản trị cơ sở dữ liệu. Một máy chủ có thể chứa nhiều cơ sở dữ liệu. Để tương tác với cơ sở dữ liệu, trước tiên bạn phải thiết lập kết nối với máy chủ. Quy trình làm việc chung của một chương trình Python tương tác với cơ sở dữ liệu dựa trên MySQL như sau:

  1. Kết nối với máy chủ MySQL.
  2. Tạo cơ sở dữ liệu mới.
  3. Kết nối với cơ sở dữ liệu mới được tạo hoặc cơ sở dữ liệu hiện có.
  4. Thực thi truy vấn SQL và tìm nạp kết quả.
  5. Thông báo cho cơ sở dữ liệu nếu có bất kỳ thay đổi nào được thực hiện đối với một bảng.
  6. Đóng kết nối với máy chủ MySQL.

Đây là quy trình công việc chung có thể khác nhau tùy thuộc vào từng ứng dụng. Nhưng bất kể ứng dụng có thể là gì, bước đầu tiên là kết nối cơ sở dữ liệu với ứng dụng của bạn.


Thiết lập kết nối

Bước đầu tiên khi tương tác với máy chủ MySQL là thiết lập kết nối. Để làm điều này, bạn cần connect() từ mysql.connector mô-đun. Hàm này nhận các tham số như host , userpassword và trả về một MySQLConnection vật. Bạn có thể nhận các thông tin xác thực này dưới dạng đầu vào từ người dùng và chuyển chúng vào connect() :

from getpass import getpass
from mysql.connector import connect, Error

try:
    with connect(
        host="localhost",
        user=input("Enter username: "),
        password=getpass("Enter password: "),
    ) as connection:
        print(connection)
except Error as e:
    print(e)

Đoạn mã trên sử dụng thông tin đăng nhập đã nhập để thiết lập kết nối với máy chủ MySQL của bạn. Đổi lại, bạn nhận được MySQLConnection đối tượng, được lưu trữ trong connection Biến đổi. Từ bây giờ, bạn sẽ sử dụng biến này để truy cập vào máy chủ MySQL của mình.

Có một số điều quan trọng cần lưu ý trong đoạn mã trên:

  • Bạn phải luôn đối phó với các trường hợp ngoại lệ có thể xảy ra trong khi thiết lập kết nối với máy chủ MySQL. Đây là lý do tại sao bạn sử dụng tryexcept chặn để bắt và in bất kỳ ngoại lệ nào mà bạn có thể gặp phải.

  • Bạn phải luôn đóng kết nối sau khi truy cập xong cơ sở dữ liệu. Việc để lại các kết nối mở không sử dụng có thể dẫn đến một số lỗi không mong muốn và các vấn đề về hiệu suất. Đoạn mã trên tận dụng lợi thế của trình quản lý ngữ cảnh bằng cách sử dụng with , tóm tắt quá trình dọn dẹp kết nối.

  • Bạn không bao giờ nên mã hóa cứng thông tin đăng nhập của mình , tức là tên người dùng và mật khẩu của bạn, trực tiếp trong một tập lệnh Python. Đây là một thực tiễn xấu để triển khai và gây ra mối đe dọa an ninh nghiêm trọng. Đoạn mã trên nhắc người dùng nhập thông tin đăng nhập. Nó sử dụng getpass tích hợp sẵn mô-đun để ẩn mật khẩu. Mặc dù điều này tốt hơn so với mã hóa cứng, nhưng có những cách khác, an toàn hơn để lưu trữ thông tin nhạy cảm, chẳng hạn như sử dụng các biến môi trường.

Bạn hiện đã thiết lập kết nối giữa chương trình và máy chủ MySQL của mình, nhưng bạn vẫn cần tạo cơ sở dữ liệu mới hoặc kết nối với cơ sở dữ liệu hiện có bên trong máy chủ.



Tạo cơ sở dữ liệu mới

Trong phần cuối cùng, bạn đã thiết lập kết nối với máy chủ MySQL của mình. Để tạo một cơ sở dữ liệu mới, bạn cần thực thi một câu lệnh SQL:

CREATE DATABASE books_db;

Câu lệnh trên sẽ tạo một cơ sở dữ liệu mới với tên books_db .

Lưu ý: Trong MySQL, bắt buộc phải đặt dấu chấm phẩy (; ) ở cuối một câu lệnh, biểu thị sự kết thúc của một truy vấn. Tuy nhiên, MySQL Connector / Python tự động thêm dấu chấm phẩy vào cuối các truy vấn của bạn, vì vậy bạn không cần sử dụng nó trong mã Python của mình.

Để thực hiện truy vấn SQL bằng Python, bạn sẽ cần sử dụng con trỏ, con trỏ này sẽ tóm tắt quyền truy cập vào các bản ghi cơ sở dữ liệu. MySQL Connector / Python cung cấp cho bạn MySQLCursor lớp khởi tạo các đối tượng có thể thực thi các truy vấn MySQL bằng Python. Một bản sao của MySQLCursor lớp còn được gọi là cursor .

cursor các đối tượng sử dụng MySQLConnection đối tượng tương tác với máy chủ MySQL của bạn. Để tạo cursor , sử dụng .cursor() phương thức kết nối connection biến:

cursor = connection.cursor()

Đoạn mã trên cung cấp cho bạn một phiên bản của MySQLCursor lớp học.

Một truy vấn cần được thực thi sẽ được gửi đến cursor.execute() ở định dạng chuỗi. Trong dịp cụ thể này, bạn sẽ gửi CREATE DATABASE truy vấn tới cursor.execute() :

from getpass import getpass
from mysql.connector import connect, Error

try:
    with connect(
        host="localhost",
        user=input("Enter username: "),
        password=getpass("Enter password: "),
    ) as connection:
        create_db_query = "CREATE DATABASE online_movie_rating"
        with connection.cursor() as cursor:
            cursor.execute(create_db_query)
except Error as e:
    print(e)

Sau khi thực thi đoạn mã trên, bạn sẽ có một cơ sở dữ liệu mới có tên là online_movie_rating trong máy chủ MySQL của bạn.

CREATE DATABASE truy vấn được lưu trữ dưới dạng chuỗi trong create_db_query biến và sau đó được chuyển tới cursor.execute() để thực hiện. Mã sử ​​dụng trình quản lý ngữ cảnh với cursor đối tượng để xử lý quá trình dọn dẹp.

Bạn có thể gặp lỗi ở đây nếu cơ sở dữ liệu có cùng tên đã tồn tại trong máy chủ của bạn. Để xác nhận điều này, bạn có thể hiển thị tên của tất cả cơ sở dữ liệu trong máy chủ của mình. Sử dụng cùng một MySQLConnection đối tượng trước đó, thực thi SHOW DATABASES tuyên bố:

>>>
>>> show_db_query = "SHOW DATABASES"
>>> with connection.cursor() as cursor:
...     cursor.execute(show_db_query)
...     for db in cursor:
...         print(db)
...
('information_schema',)
('mysql',)
('online_movie_rating',)
('performance_schema',)
('sys',)

Đoạn mã trên in tên của tất cả các cơ sở dữ liệu hiện có trong máy chủ MySQL của bạn. SHOW DATABASES lệnh cũng xuất ra một số cơ sở dữ liệu mà bạn không tạo trong máy chủ của mình, như information_schema , performance_schema , và như thế. Các cơ sở dữ liệu này được tạo tự động bởi máy chủ MySQL và cung cấp quyền truy cập vào nhiều loại siêu dữ liệu cơ sở dữ liệu và cài đặt máy chủ MySQL.

Bạn đã tạo cơ sở dữ liệu mới trong phần này bằng cách thực thi CREATE DATABASE tuyên bố. Trong phần tiếp theo, bạn sẽ thấy cách kết nối với cơ sở dữ liệu đã tồn tại.



Kết nối với cơ sở dữ liệu hiện có

Trong phần cuối cùng, bạn đã tạo một cơ sở dữ liệu mới có tên là online_movie_rating . Tuy nhiên, bạn vẫn chưa kết nối với nó. Trong nhiều trường hợp, bạn sẽ có cơ sở dữ liệu MySQL mà bạn muốn kết nối với ứng dụng Python của mình.

Bạn có thể thực hiện việc này bằng cùng một connect() chức năng mà bạn đã sử dụng trước đó bằng cách gửi một tham số bổ sung có tên là database :

from getpass import getpass
from mysql.connector import connect, Error

try:
    with connect(
        host="localhost",
        user=input("Enter username: "),
        password=getpass("Enter password: "),
        database="online_movie_rating",
    ) as connection:
        print(connection)
except Error as e:
    print(e)

Đoạn mã trên rất giống với đoạn mã kết nối mà bạn đã sử dụng trước đó. Thay đổi duy nhất ở đây là một database bổ sung tham số, trong đó tên cơ sở dữ liệu của bạn được chuyển đến connect() . Sau khi thực thi tập lệnh này, bạn sẽ được kết nối với online_movie_rating cơ sở dữ liệu.




Tạo, thay đổi và bỏ bảng

Trong phần này, bạn sẽ học cách thực hiện một số truy vấn DDL cơ bản như CREATE , DROPALTER với Python. Bạn sẽ xem nhanh cơ sở dữ liệu MySQL mà bạn sẽ sử dụng trong phần còn lại của hướng dẫn này. Bạn cũng sẽ tạo tất cả các bảng cần thiết cho cơ sở dữ liệu và tìm hiểu cách thực hiện sửa đổi trên các bảng này sau này.


Xác định lược đồ cơ sở dữ liệu

Bạn có thể bắt đầu bằng cách tạo một lược đồ cơ sở dữ liệu cho hệ thống xếp hạng phim trực tuyến. Cơ sở dữ liệu sẽ bao gồm ba bảng:

  1. movies chứa thông tin chung về phim và có các thuộc tính sau:
    • id
    • title
    • release_year
    • genre
    • collection_in_mil
  2. reviewers chứa thông tin về những người đã đăng bài đánh giá hoặc xếp hạng và có các thuộc tính sau:
    • id
    • first_name
    • last_name
  3. ratings chứa thông tin về xếp hạng đã được đăng và có các thuộc tính sau:
    • movie_id (khóa ngoại)
    • reviewer_id (khóa ngoại)
    • ratings

Hệ thống xếp hạng phim trong thế giới thực, như IMDb, sẽ cần lưu trữ một loạt các thuộc tính khác, như email, danh sách diễn viên phim, v.v. Nếu muốn, bạn có thể thêm nhiều bảng và thuộc tính vào cơ sở dữ liệu này. Nhưng ba bảng này sẽ đủ cho mục đích của hướng dẫn này.

Hình ảnh bên dưới mô tả lược đồ cơ sở dữ liệu:

Các bảng trong cơ sở dữ liệu này có liên quan đến nhau. moviesreviewers sẽ có nhiều đến nhiều mối quan hệ vì một phim có thể được nhiều người đánh giá và một người đánh giá có thể đánh giá nhiều phim. Các ratings bảng kết nối các movies bảng với reviewers bảng.



Tạo bảng bằng CREATE TABLE Tuyên bố

Bây giờ, để tạo một bảng mới trong MySQL, bạn cần sử dụng CREATE TABLE tuyên bố. Truy vấn MySQL sau sẽ tạo movies bảng cho online_movie_rating của bạn cơ sở dữ liệu:

CREATE TABLE movies(
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(100),
    release_year YEAR(4),
    genre VARCHAR(100),
    collection_in_mil INT
);

Nếu bạn đã xem xét các câu lệnh SQL trước đây, thì hầu hết các truy vấn trên có thể có ý nghĩa. Nhưng có một số khác biệt trong cú pháp MySQL mà bạn nên biết.

Ví dụ:MySQL có nhiều loại dữ liệu khác nhau cho bạn xem xét, bao gồm YEAR , INT , BIGINT , và như thế. Ngoài ra, MySQL sử dụng AUTO_INCREMENT từ khóa khi giá trị cột phải được tăng tự động khi chèn các bản ghi mới.

Để tạo một bảng mới, bạn cần chuyển truy vấn này tới cursor.execute() , chấp nhận truy vấn MySQL và thực thi truy vấn trên cơ sở dữ liệu MySQL được kết nối:

create_movies_table_query = """
CREATE TABLE movies(
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(100),
    release_year YEAR(4),
    genre VARCHAR(100),
    collection_in_mil INT
)
"""
with connection.cursor() as cursor:
    cursor.execute(create_movies_table_query)
    connection.commit()

Bây giờ bạn có movies bảng trong cơ sở dữ liệu của bạn. Bạn vượt qua create_movies_table_query thành cursor.execute() , thực hiện việc thực thi được yêu cầu.

Lưu ý: Kết nối connection biến đề cập đến MySQLConnection đối tượng đã được trả lại khi bạn kết nối với cơ sở dữ liệu của mình.

Ngoài ra, hãy chú ý đến connection.commit() câu lệnh ở cuối mã. Theo mặc định, trình kết nối MySQL của bạn không tự động gửi các giao dịch. Trong MySQL, các sửa đổi được đề cập trong một giao dịch chỉ xảy ra khi bạn sử dụng COMMIT lệnh cuối cùng. Luôn gọi phương thức này sau mỗi giao dịch để thực hiện các thay đổi trong bảng thực tế.

Như bạn đã làm với movies bảng, thực thi tập lệnh sau để tạo reviewers bảng:

create_reviewers_table_query = """
CREATE TABLE reviewers (
    id INT AUTO_INCREMENT PRIMARY KEY,
    first_name VARCHAR(100),
    last_name VARCHAR(100)
)
"""
with connection.cursor() as cursor:
    cursor.execute(create_reviewers_table_query)
    connection.commit()

Nếu được yêu cầu, bạn có thể thêm thông tin khác về người đánh giá, chẳng hạn như ID email hoặc thông tin nhân khẩu học của họ. Nhưng first_namelast_name sẽ phục vụ mục đích của bạn bây giờ.

Cuối cùng, bạn có thể tạo ratings bảng sử dụng tập lệnh sau:

create_ratings_table_query = """
CREATE TABLE ratings (
    movie_id INT,
    reviewer_id INT,
    rating DECIMAL(2,1),
    FOREIGN KEY(movie_id) REFERENCES movies(id),
    FOREIGN KEY(reviewer_id) REFERENCES reviewers(id),
    PRIMARY KEY(movie_id, reviewer_id)
)
"""
with connection.cursor() as cursor:
    cursor.execute(create_ratings_table_query)
    connection.commit()

Việc triển khai các mối quan hệ khóa ngoại trong MySQL hơi khác và hạn chế so với SQL tiêu chuẩn. Trong MySQL, cả cha và con trong ràng buộc khóa ngoại phải sử dụng cùng một công cụ lưu trữ .

Công cụ lưu trữ là thành phần phần mềm cơ bản mà hệ thống quản lý cơ sở dữ liệu sử dụng để thực hiện các hoạt động SQL. Trong MySQL, các công cụ lưu trữ có hai loại khác nhau:

  1. Công cụ lưu trữ giao dịch giao dịch có an toàn không và cho phép bạn khôi phục các giao dịch bằng các lệnh đơn giản như rollback . Nhiều công cụ MySQL phổ biến, bao gồm cả InnoDB và NDB, thuộc loại này.

  2. Công cụ lưu trữ không giao dịch phụ thuộc vào mã thủ công phức tạp để hoàn tác các câu lệnh được cam kết trên cơ sở dữ liệu. MyISAM, MEMORY và nhiều công cụ MySQL khác là không thể giao dịch.

InnoDB là công cụ lưu trữ mặc định và phổ biến nhất. Nó giúp duy trì tính toàn vẹn của dữ liệu bằng cách hỗ trợ các ràng buộc khóa ngoại. Điều này có nghĩa là mọi thao tác CRUD trên khóa ngoại đều được kiểm tra để đảm bảo rằng nó không dẫn đến sự mâu thuẫn giữa các bảng khác nhau.

Ngoài ra, hãy lưu ý rằng ratings bảng sử dụng các cột movie_idreviewer_id , cả hai khóa ngoại, cùng làm khóa chính . Bước này đảm bảo rằng người đánh giá không thể xếp hạng hai lần cho cùng một bộ phim.

Bạn có thể chọn sử dụng lại cùng một con trỏ cho nhiều lần thực thi. Trong trường hợp đó, tất cả các lần thực thi sẽ trở thành một giao dịch nguyên tử thay vì nhiều giao dịch riêng biệt. Ví dụ:bạn có thể thực thi tất cả CREATE TABLE các câu lệnh bằng một con trỏ và sau đó thực hiện giao dịch của bạn chỉ một lần:

with connection.cursor() as cursor:
    cursor.execute(create_movies_table_query)
    cursor.execute(create_reviewers_table_query)
    cursor.execute(create_ratings_table_query)
    connection.commit()

Đoạn mã trên trước tiên sẽ thực thi cả ba CREATE các câu lệnh. Sau đó, nó sẽ gửi một COMMIT lệnh tới máy chủ MySQL thực hiện giao dịch của bạn. Bạn cũng có thể sử dụng .rollback() để gửi một ROLLBACK tới máy chủ MySQL và xóa tất cả các thay đổi dữ liệu khỏi giao dịch.



Hiển thị một lược đồ bảng bằng cách sử dụng DESCRIBE Tuyên bố

Bây giờ, bạn đã tạo tất cả ba bảng, bạn có thể xem lược đồ của chúng bằng cách sử dụng câu lệnh SQL sau:

DESCRIBE <table_name>;

Để lấy lại một số kết quả từ cursor đối tượng, bạn cần sử dụng cursor.fetchall() . Phương thức này tìm nạp tất cả các hàng từ câu lệnh được thực thi cuối cùng. Giả sử bạn đã có MySQLConnection đối tượng trong connection biến, bạn có thể in ra tất cả các kết quả được tìm nạp bởi cursor.fetchall() :

>>>
>>> show_table_query = "DESCRIBE movies"
>>> with connection.cursor() as cursor:
...     cursor.execute(show_table_query)
...     # Fetch rows from last executed query
...     result = cursor.fetchall()
...     for row in result:
...         print(row)
...
('id', 'int(11)', 'NO', 'PRI', None, 'auto_increment')
('title', 'varchar(100)', 'YES', '', None, '')
('release_year', 'year(4)', 'YES', '', None, '')
('genre', 'varchar(100)', 'YES', '', None, '')
('collection_in_mil', 'int(11)', 'YES', '', None, '')

Sau khi thực thi đoạn mã trên, bạn sẽ nhận được một bảng chứa thông tin về tất cả các cột trong movies bàn. Đối với mỗi cột, bạn sẽ nhận được các thông tin chi tiết như kiểu dữ liệu của cột, liệu cột đó có phải là khóa chính hay không, v.v.



Sửa đổi lược đồ bảng bằng ALTER Tuyên bố

Trong movies bảng, bạn có một cột được gọi là collection_in_mil , chứa hàng triệu đô la doanh thu phòng vé của một bộ phim. Bạn có thể viết câu lệnh MySQL sau để sửa đổi kiểu dữ liệu của collection_in_mil thuộc tính từ INT thành DECIMAL :

ALTER TABLE movies MODIFY COLUMN collection_in_mil DECIMAL(4,1);

DECIMAL(4,1) nghĩa là một số thập phân có thể có tối đa 4 chữ số, trong đó 1 là số thập phân, chẳng hạn như 120.1 , 3.4 , 38.0 , và như thế. Sau khi thực thi ALTER TABLE , bạn có thể hiển thị lược đồ bảng đã cập nhật bằng cách sử dụng DESCRIBE :

>>>
>>> alter_table_query = """
... ALTER TABLE movies
... MODIFY COLUMN collection_in_mil DECIMAL(4,1)
... """
>>> show_table_query = "DESCRIBE movies"
>>> with connection.cursor() as cursor:
...     cursor.execute(alter_table_query)
...     cursor.execute(show_table_query)
...     # Fetch rows from last executed query
...     result = cursor.fetchall()
...     print("Movie Table Schema after alteration:")
...     for row in result:
...         print(row)
...
Movie Table Schema after alteration
('id', 'int(11)', 'NO', 'PRI', None, 'auto_increment')
('title', 'varchar(100)', 'YES', '', None, '')
('release_year', 'year(4)', 'YES', '', None, '')
('genre', 'varchar(100)', 'YES', '', None, '')
('collection_in_mil', 'decimal(4,1)', 'YES', '', None, '')

Như được hiển thị trong đầu ra, collection_in_mil thuộc tính bây giờ là loại DECIMAL(4,1) . Cũng lưu ý rằng trong đoạn mã trên, bạn gọi cursor.execute() hai lần. Nhưng cursor.fetchall() chỉ tìm nạp các hàng từ truy vấn được thực thi cuối cùng, đó là show_table_query .



Xóa bảng bằng DROP Tuyên bố

Để xóa một bảng, bạn cần thực thi DROP TABLE trong MySQL. Xóa bảng là một hành động không thể thay đổi tiến trình. Nếu bạn thực thi mã bên dưới, thì bạn sẽ cần gọi CREATE TABLE truy vấn lại để sử dụng ratings trong các phần sắp tới.

Để xóa ratings bảng, gửi drop_table_query thành cursor.execute() :

drop_table_query = "DROP TABLE ratings"
with connection.cursor() as cursor:
    cursor.execute(drop_table_query)

Nếu bạn thực thi đoạn mã trên, bạn sẽ xóa thành công ratings bảng.




Chèn bản ghi vào bảng

Trong phần cuối cùng, bạn đã tạo ba bảng trong cơ sở dữ liệu của mình:movies , reviewersratings . Bây giờ bạn cần điền dữ liệu vào các bảng này. Phần này sẽ trình bày hai cách khác nhau để chèn bản ghi trong Trình kết nối MySQL cho Python.

Phương thức đầu tiên, .execute() , hoạt động tốt khi số lượng bản ghi ít và các bản ghi có thể được mã hóa cứng. Phương thức thứ hai, .executemany() , phổ biến hơn và phù hợp hơn với các tình huống trong thế giới thực.


Sử dụng .execute()

Cách tiếp cận đầu tiên sử dụng cùng một cursor.execute() phương pháp mà bạn đang sử dụng cho đến bây giờ. Bạn viết INSERT INTO truy vấn trong một chuỗi và chuyển nó tới cursor.execute() . Bạn có thể sử dụng phương pháp này để chèn dữ liệu vào movies bảng.

Để tham khảo, movies bảng có năm thuộc tính:

  1. id
  2. title
  3. release_year
  4. genre
  5. collection_in_mil

Bạn không cần thêm dữ liệu cho id dưới dạng AUTO_INCREMENT tự động tính toán id cho bạn. Tập lệnh sau chèn các bản ghi vào movies bảng:

insert_movies_query = """
INSERT INTO movies (title, release_year, genre, collection_in_mil)
VALUES
    ("Forrest Gump", 1994, "Drama", 330.2),
    ("3 Idiots", 2009, "Drama", 2.4),
    ("Eternal Sunshine of the Spotless Mind", 2004, "Drama", 34.5),
    ("Good Will Hunting", 1997, "Drama", 138.1),
    ("Skyfall", 2012, "Action", 304.6),
    ("Gladiator", 2000, "Action", 188.7),
    ("Black", 2005, "Drama", 3.0),
    ("Titanic", 1997, "Romance", 659.2),
    ("The Shawshank Redemption", 1994, "Drama",28.4),
    ("Udaan", 2010, "Drama", 1.5),
    ("Home Alone", 1990, "Comedy", 286.9),
    ("Casablanca", 1942, "Romance", 1.0),
    ("Avengers: Endgame", 2019, "Action", 858.8),
    ("Night of the Living Dead", 1968, "Horror", 2.5),
    ("The Godfather", 1972, "Crime", 135.6),
    ("Haider", 2014, "Action", 4.2),
    ("Inception", 2010, "Adventure", 293.7),
    ("Evil", 2003, "Horror", 1.3),
    ("Toy Story 4", 2019, "Animation", 434.9),
    ("Air Force One", 1997, "Drama", 138.1),
    ("The Dark Knight", 2008, "Action",535.4),
    ("Bhaag Milkha Bhaag", 2013, "Sport", 4.1),
    ("The Lion King", 1994, "Animation", 423.6),
    ("Pulp Fiction", 1994, "Crime", 108.8),
    ("Kai Po Che", 2013, "Sport", 6.0),
    ("Beasts of No Nation", 2015, "War", 1.4),
    ("Andadhun", 2018, "Thriller", 2.9),
    ("The Silence of the Lambs", 1991, "Crime", 68.2),
    ("Deadpool", 2016, "Action", 363.6),
    ("Drishyam", 2015, "Mystery", 3.0)
"""
with connection.cursor() as cursor:
    cursor.execute(insert_movies_query)
    connection.commit()

The movies table is now loaded with thirty records. The code calls connection.commit() cuối cùng. It’s crucial to call .commit() after preforming any modifications to a table.



Using .executemany()

The previous approach is more suitable when the number of records is fairly small and you can write these records directly into the code. But this is rarely true. You’ll often have this data stored in some other file, or the data will be generated by a different script and will need to be added to the MySQL database.

This is where .executemany() comes in handy. It accepts two parameters:

  1. A query that contains placeholders for the records that need to be inserted
  2. A list that contains all records that you wish to insert

The following example inserts records for the reviewers table:

insert_reviewers_query = """
INSERT INTO reviewers
(first_name, last_name)
VALUES ( %s, %s )
"""
reviewers_records = [
    ("Chaitanya", "Baweja"),
    ("Mary", "Cooper"),
    ("John", "Wayne"),
    ("Thomas", "Stoneman"),
    ("Penny", "Hofstadter"),
    ("Mitchell", "Marsh"),
    ("Wyatt", "Skaggs"),
    ("Andre", "Veiga"),
    ("Sheldon", "Cooper"),
    ("Kimbra", "Masters"),
    ("Kat", "Dennings"),
    ("Bruce", "Wayne"),
    ("Domingo", "Cortes"),
    ("Rajesh", "Koothrappali"),
    ("Ben", "Glocker"),
    ("Mahinder", "Dhoni"),
    ("Akbar", "Khan"),
    ("Howard", "Wolowitz"),
    ("Pinkie", "Petit"),
    ("Gurkaran", "Singh"),
    ("Amy", "Farah Fowler"),
    ("Marlon", "Crafford"),
]
with connection.cursor() as cursor:
    cursor.executemany(insert_reviewers_query, reviewers_records)
    connection.commit()

In the script above, you pass both the query and the list of records as arguments to .executemany() . These records could have been fetched from a file or from the user and stored in the reviewers_records list.

The code uses %s as a placeholder for the two strings that had to be inserted in the insert_reviewers_query . Placeholders act as format specifiers and help reserve a spot for a variable inside a string. The specified variable is then added to this spot during execution.

You can similarly use .executemany() to insert records in the ratings table:

insert_ratings_query = """
INSERT INTO ratings
(rating, movie_id, reviewer_id)
VALUES ( %s, %s, %s)
"""
ratings_records = [
    (6.4, 17, 5), (5.6, 19, 1), (6.3, 22, 14), (5.1, 21, 17),
    (5.0, 5, 5), (6.5, 21, 5), (8.5, 30, 13), (9.7, 6, 4),
    (8.5, 24, 12), (9.9, 14, 9), (8.7, 26, 14), (9.9, 6, 10),
    (5.1, 30, 6), (5.4, 18, 16), (6.2, 6, 20), (7.3, 21, 19),
    (8.1, 17, 18), (5.0, 7, 2), (9.8, 23, 3), (8.0, 22, 9),
    (8.5, 11, 13), (5.0, 5, 11), (5.7, 8, 2), (7.6, 25, 19),
    (5.2, 18, 15), (9.7, 13, 3), (5.8, 18, 8), (5.8, 30, 15),
    (8.4, 21, 18), (6.2, 23, 16), (7.0, 10, 18), (9.5, 30, 20),
    (8.9, 3, 19), (6.4, 12, 2), (7.8, 12, 22), (9.9, 15, 13),
    (7.5, 20, 17), (9.0, 25, 6), (8.5, 23, 2), (5.3, 30, 17),
    (6.4, 5, 10), (8.1, 5, 21), (5.7, 22, 1), (6.3, 28, 4),
    (9.8, 13, 1)
]
with connection.cursor() as cursor:
    cursor.executemany(insert_ratings_query, ratings_records)
    connection.commit()

All three tables are now populated with data. You now have a fully functional online movie rating database. The next step is to understand how to interact with this database.




Reading Records From the Database

Until now, you’ve been building your database. Now it’s time to perform some queries on it and find some interesting properties from this dataset. In this section, you’ll learn how to read records from database tables using the SELECT statement.


Reading Records Using the SELECT Statement

To retrieve records, you need to send a SELECT query to cursor.execute() . Then you use cursor.fetchall() to extract the retrieved table in the form of a list of rows or records.

Try writing a MySQL query to select all records from the movies table and send it to .execute() :

>>>
>>> select_movies_query = "SELECT * FROM movies LIMIT 5"
>>> with connection.cursor() as cursor:
...     cursor.execute(select_movies_query)
...     result = cursor.fetchall()
...     for row in result:
...         print(row)
...
(1, 'Forrest Gump', 1994, 'Drama', Decimal('330.2'))
(2, '3 Idiots', 2009, 'Drama', Decimal('2.4'))
(3, 'Eternal Sunshine of the Spotless Mind', 2004, 'Drama', Decimal('34.5'))
(4, 'Good Will Hunting', 1997, 'Drama', Decimal('138.1'))
(5, 'Skyfall', 2012, 'Action', Decimal('304.6'))

The result variable holds the records returned from using .fetchall() . It’s a list of tuples representing individual records from the table.

In the query above, you use the LIMIT clause to constrain the number of rows that are received from the SELECT tuyên bố. Developers often use LIMIT to perform pagination when handling large volumes of data.

In MySQL, the LIMIT clause takes one or two nonnegative numeric arguments. When using one argument, you specify the maximum number of rows to return. Since your query includes LIMIT 5 , only the first 5 records are fetched. When using both arguments, you can also specify the offset of the first row to return:

SELECT * FROM movies LIMIT 2,5;

The first argument specifies an offset of 2 , and the second argument constrains the number of returned rows to 5 . The above query will return rows 3 to 7.

You can also query for selected columns:

>>>
>>> select_movies_query = "SELECT title, release_year FROM movies LIMIT 5"
>>> with connection.cursor() as cursor:
...     cursor.execute(select_movies_query)
...     for row in cursor.fetchall():
...         print(row)
...
('Forrest Gump', 1994)
('3 Idiots', 2009)
('Eternal Sunshine of the Spotless Mind', 2004)
('Good Will Hunting', 1997)
('Skyfall', 2012)

Now, the code outputs values only from the two specified columns:title and release_year .



Filtering Results Using the WHERE Clause

You can filter table records by specific criteria using the WHERE clause. For example, to retrieve all movies with a box office collection greater than $300 million, you could run the following query:

SELECT title, collection_in_mil
FROM movies
WHERE collection_in_mil > 300;

You can also use ORDER BY clause in the last query to sort the results from the highest to the lowest earner:

>>>
>>> select_movies_query = """
... SELECT title, collection_in_mil
... FROM movies
... WHERE collection_in_mil > 300
... ORDER BY collection_in_mil DESC
... """
>>> with connection.cursor() as cursor:
...     cursor.execute(select_movies_query)
...     for movie in cursor.fetchall():
...         print(movie)
...
('Avengers: Endgame', Decimal('858.8'))
('Titanic', Decimal('659.2'))
('The Dark Knight', Decimal('535.4'))
('Toy Story 4', Decimal('434.9'))
('The Lion King', Decimal('423.6'))
('Deadpool', Decimal('363.6'))
('Forrest Gump', Decimal('330.2'))
('Skyfall', Decimal('304.6'))

MySQL offers a plethora of string formatting operations like CONCAT for concatenating strings. Often, websites will show the movie title along with its release year to avoid confusion. To retrieve the titles of the top five grossing movies, concatenated with their release years, you can write the following query:

>>>
>>> select_movies_query = """
... SELECT CONCAT(title, " (", release_year, ")"),
...       collection_in_mil
... FROM movies
... ORDER BY collection_in_mil DESC
... LIMIT 5
... """
>>> with connection.cursor() as cursor:
...     cursor.execute(select_movies_query)
...     for movie in cursor.fetchall():
...         print(movie)
...
('Avengers: Endgame (2019)', Decimal('858.8'))
('Titanic (1997)', Decimal('659.2'))
('The Dark Knight (2008)', Decimal('535.4'))
('Toy Story 4 (2019)', Decimal('434.9'))
('The Lion King (1994)', Decimal('423.6'))

If you don’t want to use the LIMIT clause and you don’t need to fetch all the records, then the cursor object has .fetchone() and .fetchmany() methods as well:

  • .fetchone() retrieves either the next row of the result, as a tuple, or None if no more rows are available.
  • .fetchmany() retrieves the next set of rows from the result as a list of tuples. It has a size argument, which defaults to 1 , that you can use to specify the number of rows you need to fetch. If no more rows are available, then the method returns an empty list.

Try retrieving the titles of the five highest-grossing movies concatenated with their release years again, but this time use .fetchmany() :

>>>
>>> select_movies_query = """
... SELECT CONCAT(title, " (", release_year, ")"),
...       collection_in_mil
... FROM movies
... ORDER BY collection_in_mil DESC
... """
>>> with connection.cursor() as cursor:
...     cursor.execute(select_movies_query)
...     for movie in cursor.fetchmany(size=5):
...         print(movie)
...     cursor.fetchall()
...
('Avengers: Endgame (2019)', Decimal('858.8'))
('Titanic (1997)', Decimal('659.2'))
('The Dark Knight (2008)', Decimal('535.4'))
('Toy Story 4 (2019)', Decimal('434.9'))
('The Lion King (1994)', Decimal('423.6'))

The output with .fetchmany() is similar to what you received when you used the LIMIT clause. You might have noticed the additional cursor.fetchall() call at the end. You do this to clean all the remaining results that weren’t read by .fetchmany() .

It’s necessary to clean all unread results before executing any other statements on the same connection. Otherwise, an InternalError: Unread result found exception will be raised.




Handling Multiple Tables Using the JOIN Statement

If you found the queries in the last section to be quite straightforward, don’t worry. You can make your SELECT queries as complex as you want using the same methods from the last section.

Let’s look at some slightly more complex JOIN queries. If you want to find out the name of the top five highest-rated movies in your database, then you can run the following query:

>>>
>>> select_movies_query = """
... SELECT title, AVG(rating) as average_rating
... FROM ratings
... INNER JOIN movies
...     ON movies.id = ratings.movie_id
... GROUP BY movie_id
... ORDER BY average_rating DESC
... LIMIT 5
... """
>>> with connection.cursor() as cursor:
...     cursor.execute(select_movies_query)
...     for movie in cursor.fetchall():
...         print(movie)
...
('Night of the Living Dead', Decimal('9.90000'))
('The Godfather', Decimal('9.90000'))
('Avengers: Endgame', Decimal('9.75000'))
('Eternal Sunshine of the Spotless Mind', Decimal('8.90000'))
('Beasts of No Nation', Decimal('8.70000'))

As shown above, Night of the Living Dead and The Godfather are tied as the highest-rated movies in your online_movie_rating database.

To find the name of the reviewer who gave the most ratings, write the following query:

>>>
>>> select_movies_query = """
... SELECT CONCAT(first_name, " ", last_name), COUNT(*) as num
... FROM reviewers
... INNER JOIN ratings
...     ON reviewers.id = ratings.reviewer_id
... GROUP BY reviewer_id
... ORDER BY num DESC
... LIMIT 1
... """
>>> with connection.cursor() as cursor:
...     cursor.execute(select_movies_query)
...     for movie in cursor.fetchall():
...         print(movie)
...
('Mary Cooper', 4)

Mary Cooper is the most frequent reviewer in this database. As seen above, it doesn’t matter how complicated the query is because it’s ultimately handled by the MySQL server. Your process for executing a query will always remain the same:pass the query to cursor.execute() and fetch the results using .fetchall() .



Updating and Deleting Records From the Database

In this section, you’ll be updating and deleting records from the database. Both of these operations can be performed on either a single record or multiple records in the table. You’ll select the rows that need to be modified using the WHERE clause.


UPDATE Command

One of the reviewers in your database, Amy Farah Fowler , is now married to Sheldon Cooper . Her last name has now changed to Cooper , so you need to update your database accordingly. For updating records, MySQL uses the UPDATE statement:

update_query = """
UPDATE
    reviewers
SET
    last_name = "Cooper"
WHERE
    first_name = "Amy"
"""
with connection.cursor() as cursor:
    cursor.execute(update_query)
    connection.commit()

The code passes the update query to cursor.execute() , and .commit() brings the required changes to the reviewers table.

Note: In the UPDATE query, the WHERE clause helps specify the records that need to be updated. If you don’t use WHERE , then all records will be updated!

Suppose you need to provide an option that allows reviewers to modify ratings. A reviewer will provide three values, movie_id , reviewer_id , and the new rating . The code will display the record after performing the specified modification.

Assuming that movie_id = 18 , reviewer_id = 15 , and the new rating = 5.0 , you can use the following MySQL queries to perform the required modification:

UPDATE
    ratings
SET
    rating = 5.0
WHERE
    movie_id = 18 AND reviewer_id = 15;

SELECT *
FROM ratings
WHERE
    movie_id = 18 AND reviewer_id = 15;

The above queries first update the rating and then display it. You can create a complete Python script that establises a connection with the database and allows the reviewer to modify a rating:

from getpass import getpass
from mysql.connector import connect, Error

movie_id = input("Enter movie id: ")
reviewer_id = input("Enter reviewer id: ")
new_rating = input("Enter new rating: ")
update_query = """
UPDATE
    ratings
SET
    rating = "%s"
WHERE
    movie_id = "%s" AND reviewer_id = "%s";

SELECT *
FROM ratings
WHERE
    movie_id = "%s" AND reviewer_id = "%s"
""" % (
    new_rating,
    movie_id,
    reviewer_id,
    movie_id,
    reviewer_id,
)

try:
    with connect(
        host="localhost",
        user=input("Enter username: "),
        password=getpass("Enter password: "),
        database="online_movie_rating",
    ) as connection:
        with connection.cursor() as cursor:
            for result in cursor.execute(update_query, multi=True):
                if result.with_rows:
                    print(result.fetchall())
            connection.commit()
except Error as e:
    print(e)

Save this code to a file named modify_ratings.py . The above code uses %s placeholders to insert the received input in the update_query sợi dây. For the first time in this tutorial, you have multiple queries inside a single string. To pass multiple queries to a single cursor.execute() , you need to set the method’s multi argument to True .

If multi is True , then cursor.execute() returns an iterator. Each item in the iterator corresponds to a cursor object that executes a statement passed in the query. The above code runs a for loop on this iterator and then calls .fetchall() on each cursor object.

Note: Running .fetchall() on all cursor objects is important. To execute a new statement on the same connection, you must ensure that there are no unread results from previous executions. If there are unread results, then you’ll receive an exception.

If no result set is fetched on an operation, then .fetchall() raises an exception. To avoid this error, in the code above you use the cursor.with_rows property, which indicates whether the most recently executed operation produced rows.

While this code should solve your purpose, the WHERE clause is a prime target for web hackers in its current state. It’s vulnerable to what is called a SQL injection attack, which can allow malicious actors to either corrupt or misuse your database.

Warning :Don’t try the below inputs on your database! They will corrupt your table and you’ll need to recreate it.

For example, if a user sends movie_id=18 , reviewer_id=15 , and the new rating=5.0 as input, then the output looks like this:

$ python modify_ratings.py
Enter movie id: 18
Enter reviewer id: 15
Enter new rating: 5.0
Enter username: <user_name>
Enter password:
[(18, 15, Decimal('5.0'))]

The rating with movie_id=18 and reviewer_id=15 has been changed to 5.0 . But if you were hacker, then you might send a hidden command in your input:

$ python modify_ratings.py
Enter movie id: 18
Enter reviewer id: 15"; UPDATE reviewers SET last_name = "A
Enter new rating: 5.0
Enter username: <user_name>
Enter password:
[(18, 15, Decimal('5.0'))]

Again, the output shows that the specified rating has been changed to 5.0 . What’s changed?

The hacker sneaked in an update query while entering the reviewer_id . The update query, update reviewers set last_name = "A , changes the last_name of all records in the reviewers table to "A" . You can see this change if you print out the reviewers table:

>>>
>>> select_query = """
... SELECT first_name, last_name
... FROM reviewers
... """
>>> with connection.cursor() as cursor:
...     cursor.execute(select_query)
...     for reviewer in cursor.fetchall():
...         print(reviewer)
...
('Chaitanya', 'A')
('Mary', 'A')
('John', 'A')
('Thomas', 'A')
('Penny', 'A')
('Mitchell', 'A')
('Wyatt', 'A')
('Andre', 'A')
('Sheldon', 'A')
('Kimbra', 'A')
('Kat', 'A')
('Bruce', 'A')
('Domingo', 'A')
('Rajesh', 'A')
('Ben', 'A')
('Mahinder', 'A')
('Akbar', 'A')
('Howard', 'A')
('Pinkie', 'A')
('Gurkaran', 'A')
('Amy', 'A')
('Marlon', 'A')

The above code displays the first_name and last_name for all records in the reviewers bàn. The SQL injection attack corrupted this table by changing the last_name of all records to "A" .

There’s a quick fix to prevent such attacks. Don’t add the query values provided by the user directly to your query string. Instead, update the modify_ratings.py script to send these query values as arguments to .execute() :

from getpass import getpass
from mysql.connector import connect, Error

movie_id = input("Enter movie id: ")
reviewer_id = input("Enter reviewer id: ")
new_rating = input("Enter new rating: ")
update_query = """
UPDATE
    ratings
SET
    rating = %s
WHERE
    movie_id = %s AND reviewer_id = %s;

SELECT *
FROM ratings
WHERE
    movie_id = %s AND reviewer_id = %s
"""
val_tuple = (
    new_rating,
    movie_id,
    reviewer_id,
    movie_id,
    reviewer_id,
)

try:
    with connect(
        host="localhost",
        user=input("Enter username: "),
        password=getpass("Enter password: "),
        database="online_movie_rating",
    ) as connection:
        with connection.cursor() as cursor:
            for result in cursor.execute(update_query, val_tuple, multi=True):
                if result.with_rows:
                    print(result.fetchall())
            connection.commit()
except Error as e:
    print(e)

Notice that the %s placeholders are no longer in string quotes. Strings passed to the placeholders might contain some special characters. If necessary, these can be correctly escaped by the underlying library.

cursor.execute() makes sure that the values in the tuple received as argument are of the required data type. If a user tries to sneak in some problematic characters, then the code will raise an exception:

$ python modify_ratings.py
Enter movie id: 18
Enter reviewer id: 15"; UPDATE reviewers SET last_name = "A
Enter new rating: 5.0
Enter username: <user_name>
Enter password:
1292 (22007): Truncated incorrect DOUBLE value: '15";
UPDATE reviewers SET last_name = "A'

cursor.execute() will raise an exception if it finds any unwanted characters in the user input. You should use this approach whenever you incorporate user input in a query. There are other ways of preventing SQL injection attacks as well.



DELETE Command

Deleting records works very similarly to updating records. You use the DELETE statement to remove selected records.

Note: Deleting is an irreversible tiến trình. If you don’t use the WHERE clause, then all records from the specified table will be deleted. You’ll need to run the INSERT INTO query again to get back the deleted records.

It’s recommended that you first run a SELECT query with the same filter to make sure that you’re deleting the right records. For example, to remove all ratings given by reviewer_id = 2 , you should first run the corresponding SELECT query:

>>>
>>> select_movies_query = """
... SELECT reviewer_id, movie_id FROM ratings
... WHERE reviewer_id = 2
... """
>>> with connection.cursor() as cursor:
...     cursor.execute(select_movies_query)
...     for movie in cursor.fetchall():
...         print(movie)
...
(2, 7)
(2, 8)
(2, 12)
(2, 23)

The above code snippet outputs the reviewer_id and movie_id for records in the ratings table where reviewer_id = 2 . Once you’ve confirmed that these are the records that you need to delete, you can run a DELETE query with the same filter:

delete_query = "DELETE FROM ratings WHERE reviewer_id = 2"
with connection.cursor() as cursor:
    cursor.execute(delete_query)
    connection.commit()

With this query, you remove all ratings given by the reviewer with reviewer_id = 2 from the ratings table.




Other Ways to Connect Python and MySQL

In this tutorial, you saw MySQL Connector/Python, which is the officially recommended means of interacting with a MySQL database from a Python application. There are two other popular connectors:

  1. mysqlclient is a library that is a close competitor to the official connector and is actively updated with new features. Because its core is written in C, it has better performance than the pure-Python official connector. A big drawback is that it’s fairly difficult to set up and install, especially on Windows.

  2. MySQLdb is a legacy software that’s still used in commercial applications. It’s written in C and is faster than MySQL Connector/Python but is available only for Python 2.

These connectors act as interfaces between your program and a MySQL database, and you send your SQL queries through them. But many developers prefer using an object-oriented paradigm rather than SQL queries to manipulate data.

Object-relational mapping (ORM) is a technique that allows you to query and manipulate data from a database directly using an object-oriented language. An ORM library encapsulates the code needed to manipulate data, which eliminates the need to use even a tiny bit of SQL. Here are the most popular Python ORMs for SQL-based databases:

  1. SQLAlchemy is an ORM that facilitates communication between Python and other SQL databases. You can create different engines for different databases like MySQL, PostgreSQL, SQLite, and so on. SQLAlchemy is commonly used alongside the pandas library to provide complete data-handling functionality.

  2. peewee is a lightweight and fast ORM that’s quick to set up. This is quite useful when your interaction with the database is limited to extracting a few records. For example, if you need to copy selected records from a MySQL database into a CSV file, then peewee might be your best choice.

  3. Django ORM is one of the most powerful features of Django and is supplied alongside the Django web framework. It can interact with a variety of databases such as SQLite, PostgreSQL, and MySQL. Many Django-based applications use the Django ORM for data modeling and basic queries but often switch to SQLAlchemy for more complex requirements.

You might find one of these approaches to be more suitable for your application. If you’re not sure which one to use, then it’s best to go with the officially recommended MySQL Connector/Python that you saw in action in this tutorial.



Conclusion

In this tutorial, you saw how to use MySQL Connector/Python to integrate a MySQL database with your Python application. You also saw some unique features of a MySQL database that differentiate it from other SQL databases.

Along the way, you learned some programming best practices that are worth considering when it comes to establishing a connection, creating tables, and inserting and updating records in a database application. You also developed a sample MySQL database for an online movie rating system and interacted with it directly from your Python application.

In this tutorial, you learned how to:

  • Connect your Python app with a MySQL database
  • Bring data from a MySQL database into Python for further analysis
  • Execute SQL queries from your Python application
  • Handle exceptions while accessing the database
  • Prevent SQL injection attacks on your application

If you’re interested, Python also has connectors for other DBMSs like MongoDB and PostgreSQL. For more information, check out Python Database Tutorials.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. LINQ to SQL nhiều bảng bên trái kết hợp bên ngoài

  2. MySQL, tốt hơn để chèn NULL hoặc chuỗi trống?

  3. ASP.NET sử dụng SqlConnection kết nối MySQL

  4. Cách tạo tập lệnh từ sơ đồ trong MySQL Workbench

  5. Cách đặt hàng theo tên tháng trong MySQL