Best Practices For Writing MySQL Queries

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 17

Best practices for writing

MySQL queries
Tips, tricks, and best practices to apply

when writing MySQL queries


SQL REPLACE 01

SQL UPDATE with JOIN 03

SQL INSERT INTO SELECT 05

SQL DELETE 08

MySQL Index Examples 09


01

SQL REPLACE
5 tips for finding and replacing text in MySQL

1 SQL REPLACE replaces text


for ALL occurrences 2 SQL REPLACE can remove texts

-- Replace all occurrences of 'know' within a given string

USE sakila;

SELECT email,

SELECT REPLACE('know the unknown','know','foresee');


REPLACE(email,'.','_') AS newemail

-- Output: 'foresee the unforeseen'


FROM customer;

-- Add a space to the string to search for entire words only

-- Output:

MARY.SMITH@sakilacustomer.org
SELECT REPLACE('know the unknown','know ','foresee');
MARY_SMITH@sakilacustomer_org

-- Output: 'foresee the unknown'


PATRICIA.JOHNSON@sakilacustomer.org
PATRICIA_JOHNSON@sakilacustomer_org

3 Collations affect the results


of SQL REPLACE

-- REPLACE in MySQL is case- and language-sensitive.

SET @string := 'Cats are great pets and so easy to take care of. They make good companions. Having a cat around is good for children.';

SELECT REPLACE(@string,'cat','dog');

-- Output: Cats are great pets and so easy to take care of. They make good companions. Having a dog around is good for children.

-- If you capitalize the word "cat" in the query (i.e., "Cat"), the replace operation will not commence.

SELECT REPLACE(@string,'Cat','dog');

-- Output: dogs are great pets and so easy to take care of. They make good companions. Having a cat around is good for children.
02

4 SQL REPLACE can be nested

DECLARE @string = 'Cats are great pets and so easy to take care of. They make good companions. Having a cat around is good for children.';

SELECT REPLACE(REPLACE(@string,'cat','dog'),'Cat','Dog');

-- Output: Dogs are great pets and so easy to take care of. They make good companions. Having a dog around is good for children.

5 REPLACE can be used with UPDATE to store replaced texts

-- Update the customer table by replacing sakilacustomer.org with a fictitious email:

UPDATE customer

SET email = REPLACE(email,'sakilacustomer.org','sakila.gmail.com')

WHERE last_update > '2020-10-01';


03

1 Handle errors (SQL EXCEPTION) and transactions


(START TRANSACTION)

-- Service script:

ALTER TABLE customer

ADD COLUMN rating VARCHAR(20) DEFAULT NULL;

-- When an error of any kind occurs, the operation will roll back,

and the table data will not be updated.

SQL UPDATE with JOIN


DELIMITER $$

3 tips for running SQL UPDATE CREATE DEFINER = 'root'@'%'

with JOIN in MySQL PROCEDURE InsertAggregate (IN incst int UNSIGNED)

BEGIN

DECLARE ct int;

DECLARE sm decimal(5, 2);

DECLARE EXIT HANDLER FOR SQLEXCEPTION

BEGIN

ROLLBACK;

SELECT 'An error has occurred, the operation has been

rolled back, and the stored procedure has been

terminated';

END;

START TRANSACTION;

SELECT SUM(amount), COUNT(*)

FROM payment p

WHERE customer_id = incst INTO sm, ct;

UPDATE customer

SET summary = sm, avg_summary = sm / ct

WHERE customer_id = incst;

UPDATE payment

SET avg_flag = 1

WHERE customer_id = incst;

COMMIT;

END

$$

DELIMITER ;
04

2 Preview records using the SELECT statement 3 Use START TRANSACTION


-- With the SELECT statement, you can view the required records
prior to the actual update.
-- When an error of any kind occurs, the operation will roll back,

and the table data will not be updated.

SELECT c.*, r.rating FROM customer c,


(SELECT customer_id, SUM(amount),


SET @cst:=1;

CASE
START TRANSACTION;

WHEN SUM(amount) > 120 THEN 5


WHEN SUM(amount) BETWEEN 120 AND 110 THEN 4


SELECT SUM(amount), SUM(amount)/COUNT(*)

WHEN SUM(amount) BETWEEN 109 AND 100 THEN 3


FROM payment p

WHEN SUM(amount) BETWEEN 99 AND 90 THEN 2


WHERE customer_id = @cst /* AND avg_flag = 1*/

WHEN SUM(amount) > 90 THEN 1


INTO @sm, @ct;

ELSE 'No Rating'


END rating
UPDATE customer

FROM payment GROUP BY customer_id) r


SET avg_summary=@sm/@ct

WHERE c.customer_id = r.customer_id;


WHERE customer_id = @cst;


UPDATE payment


SET avg_flag = 1

UPDATE customer c JOIN


WHERE customer_id = @cst;

(SELECT customer_id, SUM(amount),


CASE
COMMIT;

WHEN SUM(amount) > 120 THEN 5


WHEN SUM(amount) BETWEEN 120 AND 110 THEN 4


WHEN SUM(amount) BETWEEN 109 AND 100 THEN 3


WHEN SUM(amount) BETWEEN 99 AND 90 THEN 2


-- Service script:

WHEN SUM(amount) > 90 THEN 1


ELSE 'No Rating'


ALTER TABLE customer

END rating
ADD COLUMN summary decimal(5, 2) DEFAULT NULL,

FROM payment GROUP BY customer_id) r


ADD COLUMN avg_summary decimal(5, 2) DEFAULT NULL;

ON c.customer_id = r.customer_id

SET c.rating = r.rating; ALTER TABLE payment

ADD COLUMN avg_flag INT DEFAULT NULL;

05

SQL INSERT INTO


SELECT
The easiest ways to handle duplicates

1 Use INSERT INTO SELECT DISTINCT

-- Create a test table with duplicate records:

CREATE TABLE rental_double AS

SELECT * FROM rental;

INSERT INTO rental_double

SELECT * FROM rental;

-- Create a result table:

INSERT INTO rental_no_double AS

SELECT DISTINCTROW rental_id, rental_date, inventory_id, customer_id, return_date, staff_id, last_update

FROM rental_double rd;

-- OR

INSERT INTO rental_no_double AS

SELECT DISTINCT rental_id, rental_date, inventory_id, customer_id, return_date, staff_id, last_update

FROM rental_double rd;


06

2 Use INSERT IGNORE and PRIMARY KEY/UNIQUE INDEX

-- Create a result table with PRIMARY KEY (rental_id) or UNIQUE INDEX (rental_id):

CREATE TABLE jordan.rental_no_double (

rental_id int NOT NULL,

rental_date datetime NOT NULL,

inventory_id mediumint UNSIGNED NOT NULL,

customer_id smallint UNSIGNED NOT NULL,

return_date datetime DEFAULT NULL,

staff_id tinyint UNSIGNED NOT NULL,

last_update timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

PRIMARY KEY (rental_id));

-- Use INSERT IGNORE - duplicates will not be added during insertion:

INSERT IGNORE INTO rental_no_double

SELECT rental_id, rental_date, inventory_id,

customer_id, return_date, staff_id, last_update

FROM rental_double;

3 Use GROUP BY

INSERT INTO rental_double

SELECT rental_id, rental_date, inventory_id,

customer_id, return_date, staff_id, last_update

GROUP BY (rental_id, rental_date, inventory_id,

customer_id, return_date, staff_id, last_update);


07

4 Use WHERE IN
-- Create a test table with an extra column and duplicate records:

SET @id:=0;

CREATE TABLE rental_double as

5 Use HAVING COUNT(*) > 1


SELECT @id:=@id+1 AS id, rental_id, rental_date, inventory_id,

-- Create a test table with an extra column and duplicate records:

customer_id, return_date ,staff_id, last_update

FROM rental;

SET @id:=0;

INSERT INTO rental_double

CREATE TABLE rental_double as

SELECT @id:=@id+1 AS id, rental_id, rental_date, inventory_id,

SELECT @id:=@id+1 AS id, rental_id, rental_date,

customer_id, return_date ,staff_id, last_update

inventory_id, customer_id, return_date,

FROM rental;

staff_id, last_update

FROM rental;

INSERT INTO rental_double

INSERT INTO rental_no_double

SELECT @id:=@id+1 AS id, rental_id, rental_date,

SELECT id, rental_id, rental_date, inventory_id,

inventory_id, customer_id, return_date,

customer_id, return_date, staff_id, last_update

staff_id, last_update

FROM rental_double

FROM rental;

WHERE ID IN (SELECT MAX(id) FROM rental_double

GROUP BY rental_id, rental_date, inventory_id,

customer_id, return_date, staff_id, last_update

HAVING COUNT(rental_id) > 1);


INSERT INTO rental_no_double

SELECT MAX(id) AS id, rental_id, rental_date,

inventory_id, customer_id, return_date,

staff_id, last_update

FROM rental_double

GROUP BY rental_id, rental_date, inventory_id,

customer_id, return_date, staff_id,

last_update

HAVING COUNT(*) > 1;


08

SQL DELETE 3 DELETE with a subquery

5 useful DELETE syntax tips for DELETE p FROM payment p

MySQL developers
?
WHERE p.customer_id = 2

AND p.staff_id IN (SELECT s.staff_id

FROM staff s

WHERE s.store_id IN (1,2)

AND s.username LIKE 'J%');

1 Delete all records 4 Limit

CREATE TABLE payment_backup AS


-- Delete 3 sorted records at a time:

SELECT * FROM payment;



DELETE FROM payment

DELETE FROM payment_backup;


WHERE customer_id = 3

ORDER BY payment_id, payment_date DESC

LIMIT 3;

2 Conditional DELETE with the WHERE clause 5 DELETE with a JOIN

-- Delete 1 record using the equality operator:


DELETE p FROM payment p


INNER JOIN staff s

DELETE FROM payment


ON s.staff_id = p.staff_id

WHERE payment_id = 150;


WHERE p.customer_id = 2


AND s.store_id IN (1,2)

-- Delete 3 records using IN:


AND s.username LIKE 'J%';

DELETE FROM payment

WHERE payment_id IN (151,152,153);


09

MySQL Index Examples


16 index examples to speed up your
SQL queries

1 Add a clustered index within CREATE TABLE

-- A clustered index is created along with the primary key:

CREATE TABLE payment (

payment_id smallint UNSIGNED NOT NULL AUTO_INCREMENT,

customer_id smallint UNSIGNED NOT NULL,

staff_id tinyint UNSIGNED NOT NULL,

3 Create a unique index that includes column prefix key parts


rental_id int DEFAULT NULL,
-- Using CREATE INDEX:

amount decimal(5, 2) NOT NULL,


payment_date datetime NOT NULL,


CREATE UNIQUE INDEX UK_customer ON customer(email (45));

last_update timestamp NULL


DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,


PRIMARY KEY (payment_id))


ENGINE = INNODB; -- Using ALTER TABLE:

ALTER TABLE customer

ADD UNIQUE INDEX UK_customer (email (45));

2 MySQL automatically creates an index for a Foreign Key

ALTER TABLE payment

ADD CONSTRAINT fk_payment_rental FOREIGN KEY (rental_id)

4 Create a filtered index


REFERENCES rental (rental_id) ON DELETE
ALTER TABLE customer

SET NULL ON UPDATE CASCADE; ADD INDEX idx_last_name (last_name);


10

5 Create a spatial index 6 Create a hash index


-- Using CREATE TABLE:
ALTER TABLE data_dict


ADD INDEX data_dict_dn USING HASH (data_name);

CREATE TABLE address (

7 Create a new index—and drop it immediately if it exists


address_id smallint unsigned NOT NULL AUTO_INCREMENT,

address varchar(50) NOT NULL,

address2 varchar(50) DEFAULT NULL,

district varchar(20) NOT NULL,

city_id smallint unsigned NOT NULL,

postal_code varchar(10) DEFAULT NULL,


ALTER TABLE address

phone varchar(20) NOT NULL,


DROP INDEX idx_location,

location geometry NOT NULL,


ADD INDEX idx_location (location);

last_update timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

PRIMARY KEY (address_id),

8 Use multi-valued indexes


SPATIAL INDEX idx_location (location));

-- Using ALTER TABLE:


-- Using CREATE TABLE only:

CREATE TABLE address (


address_id smallint unsigned NOT NULL AUTO_INCREMENT,


CREATE TABLE customers (

address varchar(50) NOT NULL,


id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,

address2 varchar(50) DEFAULT NULL,


modified DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

district varchar(20) NOT NULL,


custinfo JSON,

city_id smallint unsigned NOT NULL,


INDEX zips((CAST(custinfo->'$.zipcode' AS UNSIGNED ARRAY))));

postal_code varchar(10) DEFAULT NULL,


phone varchar(20) NOT NULL,


location geometry NOT NULL,


last_update timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,


-- Using CREATE TABLE and ALTER TABLE:

PRIMARY KEY (address_id),


SPATIAL INDEX idx_location (location));


CREATE TABLE customers (


id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,

ALTER TABLE address


modified DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

ADD SPATIAL INDEX idx_location (location);


custinfo JSON);

-- Using CREATE INDEX:


ALTER TABLE customers


ADD INDEX zips((CAST(custinfo->'$.zipcode' AS UNSIGNED ARRAY)));

CREATE TABLE address (


address_id smallint unsigned NOT NULL AUTO_INCREMENT,


address varchar(50) NOT NULL,


address2 varchar(50) DEFAULT NULL,


-- Using CREATE TABLE and CREATE INDEX:

district varchar(20) NOT NULL,


city_id smallint unsigned NOT NULL,


CREATE TABLE customers (

postal_code varchar(10) DEFAULT NULL,


id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,

phone varchar(20) NOT NULL,


modified DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

location geometry NOT NULL,


custinfo JSON);

last_update timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,


PRIMARY KEY (address_id),


SPATIAL INDEX idx_location (location));



CREATE INDEX zips

CREATE SPATIAL INDEX idx_location ON address (location); ON customers ((CAST(custinfo->'$.zipcode' AS UNSIGNED ARRAY)));

11

9 Create a unique composite index 10 Create a composite index with a multi-valued part

ALTER TABLE address


CREATE TABLE customers (

ADD UNIQUE INDEX UK_address (address, phone); id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,

modified DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

custinfo JSON);

11 Add a composite index



ALTER TABLE customers

ALTER TABLE customer


ADD INDEX comp(id, modified,

ADD INDEX idx_customer (first_name, email); (CAST(custinfo->'$.zipcode' AS UNSIGNED ARRAY)));

12 Add an index within CREATE TABLE using CONSTRAINT

CREATE TABLE address (

address_id smallint unsigned NOT NULL AUTO_INCREMENT,

address varchar(50) NOT NULL,

address2 varchar(50) DEFAULT NULL,

district varchar(20) NOT NULL,

city_id smallint unsigned NOT NULL,

postal_code varchar(10) DEFAULT NULL,

phone varchar(20) NOT NULL,

location geometry NOT NULL,

last_update timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

PRIMARY KEY (address_id),

KEY idx_fk_city_id (city_id),

CONSTRAINT fk_address_city FOREIGN KEY (city_id) REFERENCES city (city_id) ON DELETE RESTRICT ON UPDATE CASCADE);
12

13 Drop an index using IF EXISTS


DELIMITER $$

CREATE PROCEDURE `DropIndexIfExists`(


IN i_table_name VARCHAR(128),

IN i_index_name VARCHAR(128))

BEGIN

SET @tableName = i_table_name;

SET @indexName = i_index_name;

SET @indexExists = 0;

SELECT 1

INTO @indexExists

FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_NAME = @tableName

AND INDEX_NAME = @indexName;

14 Drop an index
SET @query = CONCAT('DROP INDEX ', @indexName, ' ON ', @tableName); -- Using ALTER TABLE:
IF @indexExists THEN

PREPARE stmt FROM @query;


ALTER TABLE address

EXECUTE stmt;
DROP INDEX idx_location;
DEALLOCATE PREPARE stmt;

END IF;
-- Using DROP INDEX:

END

$$
DROP INDEX idx_location

DELIMITER; ON address;

15 Create a full-text index

ALTER TABLE address

ADD
WITH
FULLTEXT INDEX IDX_address_address (address)
PARSER NGRAM;
16 Rename an index
ALTER TABLE address

ADD FULLTEXT INDEX IDX_address_address2 (address2) ALTER TABLE address


WITH PARSER MECAB; RENAME INDEX idx_location TO idx_location1;
13

dbForge Studio for MySQL:


your comprehensive IDE for MySQL databases

dbForge Studio is a multifunctional IDE SQL editor


The built-in SQL editor helps you effectively manage your SQL code with
for MySQL, which helps you handle a smart completion, syntax highlighting, formatting, refactoring, and a slew of
other productivity enhancements that let you get a sharper focus on your
variety of tasks, including operations work.
with JOINs. Context-sensitive code completion
With its help, you can instantly get With dbForge Studio, you can easily speed up your routine SQL coding by at
least 90% with context-sensitive keyword and object suggestions, which
at least 30% more effective and reduce include auto-generation of JOIN clauses. Auxiliary features include code
the time you typically spend on your snippets, column picker, wildcards, highlighting, and parameter information.

routine work with databases Instant syntax check


by about 50%. The syntax checker is one of the most valuable features integrated into the
SQL editor. Whenever the checker detects an error in the code that you are
typing, it instantly highlights the problematic place so you can fix it
immediately.

SQL formatting
It is easy to improve the readability, consistency, and standardization of your
DOWNLOAD FREE 30-DAY TRIAL code with the rich SQL formatting options offered by the Studio. Depending
on your needs, you can apply automatic, manual, or wizard-aided formatting.
14

The built-in MySQL Debugger empowers you


with automated code debugging capabilities
and makes it no longer necessary to search
for errors in your scripts manually. Its sub-
features include step-by-step execution, call
stack browsing, breakpoints, and watches.

With its help, you can easily investigate the


run-time behavior of your database objects,
locate logic errors, and debug code directly in
your IDE. This helps you avoid performance
issues and minimize possible downtime.

I WANT TO TRY!
15

Helpful resources
Here are a few bonuses to help you expand your MySQL skills.

Beginner's guide to Helpful resources to boost More MySQL insights

dbForge Studio your skills with dbForge on our blog


Studio

Get started with dbForge Studio for free today! DOWNLOAD FREE 30-DAY TRIAL

You might also like