# MySQL Note ###### tags: `work` `Self_Learning` `database` ## Basic ### Case-insensitive SQL query is case-insensitive, which means that `select *` is same as `SELECT *`, even if `SeLecT *`. ### Comma Use comma to `SELECT` multiple objects in one query. e.g., ```sql SELECT VERSION(), CURDATE(); ``` The output is: |version()|current_date| |-|-| |5.7.32|2020-11-26| ### newline, tab, whitespace insensitive ```sql SELECT * FROM my_table; ``` is equivalent to ```sql= SELECT * FROM my_table; ``` ### Math supported SQL can use as a calculator. Also support `+`, `-`, `*`, `/`, `MOD(, )`. ```sql SELECT SIN(PI()/2); ``` The output is `1`. ### Comment SQL query uses `#` to add a comment. ## Basic Command ### SELECT [doc](https://dev.mysql.com/doc/refman/5.7/en/select.html) Basically it's like a "print" function, which means it can be used to print a string. e.g., ```sql SELECT "this is a string." ``` > Double and single quotation mark are equivalent to SQL. Because it's like a "print" function, it can be used to print the particular columns: ```sql SELECT name, birth FROM people_table; ``` ### UPDATE Update value of data. ```sql UPDATE <table_name> SET <data_name>=<new_value> WHERE <condition>; ``` ### SHOW [doc](https://dev.mysql.com/doc/refman/5.7/en/show.html) * `SHOW databases`: show all databases exist on the server. * `SELECT database`: currently selected database. * `SHOW tables`: show all tables exist. ### USE [doc](https://dev.mysql.com/doc/refman/5.7/en/use.html) Use `USE <database>` to change to annother database. ### CREATE * create database ```sql CREATE DATABASE <database_name>; ``` * create table ```sql CREATE TABLE <table_name> (<data_name> <data_type>, ...); ``` Data types ([offical doc](https://dev.mysql.com/doc/refman/5.7/en/data-types.html)) include a lot of options such like: * `VARCHAR(<int>)` * `INTERGER`, `INT` * `TEXT` * `CHAR(1)` * `DATE` (YYYY-MM-DD) * `BLOB` * `NULL` ### DESCRIBE Show the structure of a table. e.g., ```sql DESCRIBE test_table; ``` --- ## Advanced create ### AUTO_INCREMENT Data type set as `auto_increment` will increase automatically. e.g., ```sql CREATE TABLE test_table (id INTEGER AUTO_INCREMENT, name TEXT); ``` Use `NULL` as value. ### PRIMARY KEY :::danger Only one primary key avaliable. ::: Data type set as `PRIMARY KEY` can make sure that each value is unique, which usually used in serial number (S/N) or id. e.g., ```sql CREATE TABLE test_table ( id INTEGER PRIMARY KEY AUTO_INCREMENT, name TEXT); ``` ### NOT NULL To force it can't be `NULL`. ```sql CREATE TABLE test_table ( id INTERGER NOT NULL, name TEXT); ``` * acceptable data: (3, null), (5, "Ted") * unacceptable data: (null, null), (null, "Tom") --- ## Insert data In this section, we use the table `tools` |data name|data type| |-|-| |SN|`INTERGER NOT NULL`| |name|`TEXT`| |buy_date|`DATE`| ### INSERT This example insert this data: |SN|name|buy_date| |-|-|-| |'oven'|1103517346|'2018-08-16'| into `tools`. We use insert: ```sql INSERT INTO tools VALUES ('oven', 1103517346, '2018-08-16'); ``` Can insert multiple data: ```sql INSERT INTO tools VALUES ('oven', 1103517346, '2018-08-16'), ('firge', 5620561572, '1999-12-10'), ('phone', 6592618265, '2011-03-23'); ``` ### Load local data Assume that there's a text file named as data.txt: ``` oven 1103517346 2018-08-16 ``` If we want to load data.txt in `tool`, use query: ```sql LOAD DATA LOCAL INFILE '/data.txt' INTO TABLE tools; ``` If we have multiple data in data.txt seperated by newline (``"\r\n"``), use this query: ```sql LOAD DATA LOCAL INFILE '/data.txt' INTO TABLE tools LINES TERMINATED BY '\r\n'; ``` --- ## FROM & WHERE (& IN & BETWEEN) ```sql SELECT what_to_select FROM which_table WHERE condition; ``` ### operator used in setting condition * operator * equality: `=` or `IS` * inequality: `>`, `<`, `<=`, `>=` > Note that the data type `date` support inequality operator. * Logical opeator `NOT`, `AND`, `OR`, `XOR` * `IS NOT NULL` check if the value is empty. ### IN ```sql SELECT * FROM people_table WHERE name IN ('Jack', 'Tom'); ``` ### BETWEEN ... AND ... ```sql SELECT * FROM people_table WHERE birth BETWEEN '1990-01-01' AND '2000-12-31'; ``` --- ## Deal with existing data (edit, remove) ### DELETE [doc](https://dev.mysql.com/doc/refman/5.7/en/delete.html) ```sql DELETE FROM fruits_table WHERE name = "apple"; ``` ### UPDATE ... SET ... [doc](https://dev.mysql.com/doc/refman/5.7/en/update.html) ```sql UPDATE fruits_table SET color = "red" WHERE name = "apple"; ``` --- ## Advanced select ### ORDER BY ```sql SELECT name, birth FROM people_table ORDER BY birth; ``` ### ORDER ... DESC Sort in reverse. ```sql SELECT name, birth FROM people_table ORDER BY birth DESC; ``` ### AS Used to set column title. ```sql SELECT CURDATE() AS curr; ``` output is: |curr| |-| |2020-11-20| It can be a string. ```sql SELECT CURDATE() AS 'current date'; ``` output is: |current date| |-| |2020-11-20| After using `AS`, it can be used in anywhere in the same query. ### LIKE SQL pattern matching enables you to use `_` to match any single character and `%` to match any number of characters (including zero characters). ```sql SELECT * FROM strings WHERE title LIKE '_b%'; ``` * acceptable: Abby, cba, 1b * unacceptable: bcc, aqbxx We can use several `_` to select particular number of characters. `_____` $\Leftrightarrow$ `12345` ### REGEXP Regular expression. ### COUNT [doc](https://dev.mysql.com/doc/refman/5.7/en/aggregate-functions.html#function_count) ```sql SELECT COUNT(*) FROM my_table; ``` ### GROUP BY Consider 4 data in `tools` like: |id|name|buydate| |-|-|-| |1|oven|2020-04-03| |2|frige|2018-09-29| |3|oven|2019-11-30| |4|hammer|2020-05-30| * If we want to list each quantity, we can use: ```sql SELECT name, COUNT(*) AS count FROM tools GROUP BY name; ``` The output is: |name|count| |-|-| |frige|1| |hammer|1| |oven|2| * We can also get the latest year of `buydate`: ```sql SELECT name, YEAR(MAX(buydate)) AS 'buy year' FROM tools GROUP BY name; ``` The output is: |name|buy year| |-|-| |frige|2018| |hammer|2020| |oven|2020| --- ## built-in functions ### CURDATE() Current date. ### TIMESTAMPDIFF() e.g. ages: ```sql SELECT name, birth, CURDATE(), TIMESTAMPDIFF(year, birth, CURDATE()) AS age FROM people_table ORDER BY birth; ``` ### YEAR(), MONTH(), DAYOFMONTH() Select particular part from a `DATE` type. e.g. ```sql YEAR(CURDATE()); MONTH(CURDATE()); DAYOFMONTH(CURDATE()); ``` ### DATE_ADD & INTERVAL `DATE_ADD` will automatically deal with the date format. ```sql DATE_ADD(CURDATE(), INTERVAL 1 MONTH) DATE_ADD(CURDATE(), INTERVAL 1 DAY) ``` ### MAX() & MIN() * Example 1: ```sql SELECT MAX(price) AS "max price" FROM shop; ``` * Example 2: Find `id`, `name` and `price` of the most expensice `merchandise`. ```sql SELECT id, name, price FROM merchandise WHERE price=(SELECT MAX(price) FROM merchandise); ``` --- ## JOIN [doc](https://dev.mysql.com/doc/refman/5.6/en/outer-join-simplification.html) ```sql select table1 [INNER/LEFT/RIGHT] JOIN table2 ON [condition] ``` Example used below are * `table1`: |id| |-| |1| |2| |3| |4| * `table2`: |id| |-| |1| |5| |3| |3| ### INNER JOIN Inner join will retain the data that meets the conditions. ```sql SELECT a.id, b.id FROM table1 AS a INNER JOIN table2 AS b ON a.id = b.id; ``` output: |id|id| |-|-| |1|1| |3|3| |3|3| #### Use Case: Use this when both sides must have corresponding values. For example, consider a list of orders and the customers who placed them. An order without a customer represents erroneous data, and a customer without an order is not of interest to us. ### LEFT JOIN Left join will base on left one. ```sql SELECT a.id, b.id FROM table1 AS a LEFT JOIN table2 AS b ON a.id = b.id; ``` output: |id|id| |-|-| |1|1| |2|null| |3|3| |3|3| |4|null| #### Use Case: Use this when one side may not have related data on the other side. For example, if we want a list of members and their orders, a LEFT JOIN is appropriate. This ensures that even members who have never placed an order will still appear in the result list. ### RIGHT JOIN Right join will base on right one. ```sql SELECT a.id, b.id FROM table1 AS a RIGHT JOIN table2 AS b ON a.id = b.id; ``` output: |id|id| |-|-| |1|1| |null|5| |null|6| |3|3| |3|3| > `a LEFT JOIN b` is equivalent to `b LEFT JOIN a`. #### Use Case: This is similar to LEFT JOIN but applies in the opposite direction. It is used when we are more interested in retaining all entries from the right table, even if there's no matching entry in the left table. ### FULL OUTER JOIN No matter it do or do not have value on left side or right side, all data will be included. #### Use Case: Use this for cases where you want to list all entries from both sides, regardless of whether there are matching entries on the other side. For instance, in a situation where we aim to list all students and the classes they take, a FULL OUTER JOIN is suitable. This approach accounts for students enrolled in multiple classes, as well as those enrolled in only one class, ensuring no student or class information is omitted even if some fields end up being NULL due to the absence of corresponding data. ### USING ```sql ON a.id=b.id ``` is equivalent to ```sql USING(id) ``` --- ## Create a new account [doc](https://dev.mysql.com/doc/refman/5.7/en/creating-accounts.html) Requires root: > in shell `mysql -u root -p` ### create user ```sql CREATE USER 'newuser'@'localhost' IDENTIFIED BY 'newpassword'; ``` ### grant privileges [doc](https://dev.mysql.com/doc/refman/5.7/en/grant.html) * demo ```sql GRANT all ON <priv_level> TO <username> WITH GRANT OPTION; ``` * <priv_level> can be * ```*``` * ```*.*``` * ```db_name.*``` * ```db_name.tbl_name``` * ```tbl_name``` * ```db_name.routine_name``` This query could be more complex. generally it looks like: ```sql GRANT ALL ON *.* TO 'newuser'@'localhost' WITH GRANT OPTION; ``` ## User-Defined Variables Use `@` and `:=`. e.g., ```sql SELECT @min_price:=min(price), @max_price:=MAX(price) FROM shop; ``` After defining variables, we can use it as a variable: ```sql SELECT * FROM shop WHERE price=@min_price OR price=@max_price; ```