Bazy danych
- relacyjne (SQL)
- nierelacyjne (NoSQL)
Główny podział poleceń w SQL
Data Definition Language (DDL): – umieszczanie, aktualizowanie lub usuwanie danych z bazy
- CREATE
- ALTER (add, delete, or modify columns in an existing table)
- DROP
- RENAME
- TRUNCATE
Data Manipulation Language (DML) – operacje na strukturach bazy danych, czyli np. tworzenie lub kasowanie tabel i baz.
- SELECT … FROM …
- INSERT … INTO … VALUES …
- UPDATE … SET … WHERE
- DELETE … FROM … WHERE …
Data Control Language (DCL) – nadawanie uprawnień do obiektów baz
- REVOKE
- GRANT
Transaction Control Language (TCL)
- COMMIT
- ROLLBACK
Primary key
Unikalny identyfikator - kolumna (lub zestaw kolumn) które zawiera(ją) unikalne wartości dla każdego rekordu w tabeli. Dozwolony jest jeden primary key na tabelę. Nie może być pusty (null). Mie każda tabela musi mieć PK.
Foreign Key
identyfikuje relację pomiędzy tabelami
Sales | Customers | ||||
---|---|---|---|---|---|
**purchase_number** | | | — | -> | customer_id | |
date_of_purchase | first_name | ||||
customer_id (FK) — | — | | | last_name | ||
email_address |
parent table - referenced table
child table - referencing table
-- add FK
ALTER TABLE sales
ADD FOREIGN KEY (customer_id) REFERENCES customers(customer_id) ON DELETE CASCADE;
-- remove FK
ALTER TABLE sales
DROP FOREIGN KEY sales_ibfk2;
Unique key
Musi zawierać unikalne wartości w przeciwieństwie do PK może mieć puste wartości (NULL). Może występować kilka Unique Key w jednej tabeli.
-- add UK
ALTER TABLE customers
ADD UNIQUE KEY (email_address);
-- remove UK
ALTER TABLE customers
DROP INDEX email_address;
Relacje
- Jeden do wielu
- wiele do jednego-
- wiele do wielu
- jeden do jednego
Całość można pogrupować jak poniżej:
- SELECT
- INSERT
- UPDATE
- DELETE
- funkcje agregujące
- JOIN
- Subqueries
SELECT
Kolejność komend:
SELECT column_name(s)
FROM table_name
WHERE conditions
GROUP BY column_name(s)
HAVING conditions
ORDER BY column_name(s)
LIMIT number;
Podstawowe operacje:
1: AND
/ OR
SELECT
* -- column1, column2
FROM
employees -- table name
WHERE -- opcjonalnie
last_name = 'Elvis' AND (gender = 'M' OR gender = 'F'); -- AND, OR, IN etc.
/*
Kolejność operatorów AND > OR
*/
2: IN/ NOT IN
SELECT * FROM employees
WHERE
first_name NOT IN ('John' , 'Mark', 'Jacob'); -- multiple conditoions, wszyscy poza
3: LIKE
SELECT * FROM employees
WHERE
first_name LIKE('_ar%'); -- Mariusz, Marcin _ pojedynczy znak, % dowolny ciąg znaków
4: BETWEEN
SELECT * FROM salaries
WHERE
salary BETWEEN 6600 AND 7000;
5: IS NOT NULL
SELECT dept_name FROM departments
WHERE
dept_no IS NOT NULL;
6: DISTINCT
SELECT DISTINCT -- jak pandas.unique(), zwraca uniklane wartości w kolumnie
hire_date
FROM
employees;
7: DESC/ASC - sortowanie rosnąco malejąco
SELECT
*
FROM
employees
ORDER BY hire_date DESC;
8: Alias - AS (nadanie nowej nazwy)
SELECT
salary, COUNT(emp_no) AS emps_with_same_salary --AS rename nowo stworzonej kolumny
FROM
salaries
WHERE
salary > 80000
GROUP BY salary
ORDER BY salary;
9: HAVING - używane po GROUP By żeby doprecyzować zapytanie
SELECT
emp_no, AVG(salary)
FROM
salaries
GROUP BY emp_no
HAVING AVG(salary) > 120000
ORDER BY emp_no;
Aggregate functions: GROUP BY i HAVING
Ogólne warunki: WHERE (używane jest przed GROUP BY)
10: LIMIT
SELECT
*
FROM
dept_emp
ORDER BY salaries DESC -- odpowiednik pandas.head(10) .tail(10)
LIMIT 100;
INSERT
Przykładowa składnia:
INSERT INTO employees
VALUES
(
999903, -- brak apostrofów - Integer
'1977-09-14',
'Johnathan',
'Creek',
'M',
'1999-01-01'
);
UPDATE
UPDATE departments
SET
dept_name = 'Data Analysis'
WHERE
dept_no = 'd010'; -- bez tego warunku nadpisz ewszystkie rekordy
Pamiętać o COMMIT i ROLLBACK
DELETE
ON DELETE CASCADE - przy usuwaniu rodzica usuwa wartości w tabeli dziecka
DELETE FROM departments
WHERE
dept_no = '5';
DROP vs TRUNCATE vs DELETE
DROP:
-
usuwa zawartość
- usuwa indexy
- usuwa constrains
- nie może być cofnięty poprzez ROLLBACK
TRUNCATE:
- odpowiednik DELETE bez zdefiniowanego WHERE
- usuwa zawartość, struktura zostaje zachowana
- wartości auto-increment zostaną zresetowane (1,2,3 - X - 5 –> 1, 2,3 )
DELETE:
- usuwa rekordy rzędami
- wartości auto-increment pozostają zachowane ()
- Jest wolniejsze od TRUNCATE (jeżeli używamy go w taki sam sposób, tzn. bez WHERE)
AGG
Przykłady funkcji agregujących: COUNT() SUM() MIN() MAX() AVG()
SELECT
COUNT(DISTINCT first_names) -- pandas.nunique()
FROM
employees
COUNT() -- zlicza wartości, jako jedyna działa z non-numeruc data
COUNT(*) -- zlicza wartości (lącznie z polami typu NULL)
COUNT(DISTINCT) -- zlicza unikalne wartości
SUM()
MIN()
MAX()
AVG()
ROUND(#, decimal_places) -- decimal place jest opcjonalny
IFNULL(expression_not_null, expression_null)
COALESCE(expr_1, expr_2, exp_n3 ...)--IFNULL z więcej niż dwoma parametrami
JOINS
1: INNER JOIN - zwraca tylko część wspólną
SELECT e.emp_no,
e.first_name,
e.last_name,
dm.dept_no,
e.hire_date
FROM employees e
JOIN dept_manager dm
ON e.emp_no = dm.emp_no;
2: LEFT JOIN - zwraca część wspólną + wartości z lewej tabeli które nie mają pokrycia w prawej
3: RIGHT JOIN - zwraca część wspólną + wartości z prawej tabeli które nie mają pokrycia w lewej (jak odwrócimy tabele w LEFT JOIN to otrzymamy to samo)
4: CROSS JOIN
5: UNION / UNION ALL
6: self join
CASES
SELECT e.emp_no,
e.first_name,
e.last_name,
CASE
WHEN dm.emp_no IS NOT NULL THEN 'Manager'
ELSE 'Employee'
end AS is_manager
FROM employees e
LEFT JOIN dept_manager dm
ON dm.emp_no = e.emp_no
WHERE e.emp_no > 109990;
SQL VIEW
Wirtualna tabela utworzona z innej istniejącej tabeli lub tabel. “Migawka” z zapisanym stanem zdefiniowanego wcześniej zapytania. Jest ona uaktualniana automatycznie wraz ze zmieniającymi się danymi w oryginalnej tabeli.
CREATE OR replace VIEW v_manager_avg_salary
AS
SELECT Round(Avg(salary), 2)
FROM salaries s
join dept_manager m
ON s.emp_no = m.emp_no;
Indeksy
s
SELECT *
FROM salaries
WHERE salary > 89000;
CREATE INDEX i_salary ON salaries(salary);
SELECT *
FROM salaries
WHERE salary > 89000;
Stored routines
- stored procedures (nie zwracają wartości) Użycie:
call
procedure; - functions (user defined, built-in - zwracają pojedynczą wartość) Użycie:
select
function;
Procedura:
DELIMITER $$
CREATE PROCEDURE avg_salary()
BEGIN
SELECT
AVG(salary)
FROM
salaries;
END$$
DELIMITER ;
--to use type:
CALL avg_salary;
CALL avg_salary();
CALL employees.avg_salary;
CALL employees.avg_salary();
Funkcja:
DELIMITER $$
CREATE FUNCTION emp_info(p_first_name varchar(255), p_last_name varchar(255))
RETURNS decimal(10, 2)
BEGIN
DECLARE v_max_from_date date;
DECLARE v_salary decimal(10, 2);
SELECT
MAX(from_date) INTO v_max_from_date
FROM
employees e
JOIN
salaries s
ON e.emp_no = s.emp_no
WHERE
e.first_name = p_first_name
AND e.last_name = p_last_name;
SELECT
s.salary INTO v_salary
FROM
employees e
JOIN
salaries s
ON e.emp_no = s.emp_no
WHERE
e.first_name = p_first_name
AND e.last_name = p_last_name
AND s.from_date = v_max_from_date;
RETURN v_salary;
END $$
DELIMITER ;
SELECT
EMP_INFO('Aruna', 'Journel');
SQLite
Pierwszym podejściem do baz danych był dla mnie SQLite, wypisałem sobie tutaj kilka informacji które zwróciły moją uwagę.
Tworzenie nowej tabeli
Ogólny kod:
CREATE TABLE [IF NOT EXISTS] [schema_name].table_name (
column_1 data_type PRIMARY KEY,
column_2 data_type NOT NULL,
column_3 data_type DEFAULT 0,
table_constraints
) [WITHOUT ROWID];
Przykład w python:
"""CREATE TABLE "{table_name}" (
"offer_id" INTEGER NOT NULL,
"city" TEXT,
"region" TEXT,
"model" TEXT,
"year" INTEGER,
"mileage" INTEGER,
"fuel_type" TEXT,
"displacement" INTEGER,
"price" INTEGER,
"currency" TEXT,
"pub_date" TEXT,
"duration" INTEGER,
"end_price" INTEGER
);""".format(table_name=table_name)
Kopiowanie danych do kolejnej tabeli
INSERT INTO new_table (offer_id,city,region,model)
SELECT offer_id,city,region,model FROM otomoto_20200101
UNION
SELECT offer_id,city,region,model FROM otomoto_20200102
Kopiowanie zawartości kolumny
Z jednej tabeli do drugiej jeżeli Id jest takie samo
UPDATE mtable
SET pub_date = (
SELECT pub_date FROM otomoto_20200102
WHERE (mtable.offer_id) = (otomoto_20200102.offer_id))
WHERE pub_date is null AND ((offer_id) IN (SELECT offer_id FROM otomoto_20200102));
Zapisywanie długich zapytań
W pythonie powinno się to robić od trzech apostrofów, cudzysłowów, można wtedy dowolnie łamać tekst wewnątrz.
create_users = """
INSERT INTO
cars (offer_id,city,region,model,year,mileage,fuel_type,displacement,price,currency,pub_date,duration,end_price)
VALUES
(6069449316,'Prudnik','Opolskie','Toyota Yaris II',2009,153000,'Diesel',-1,12999,'PLN','2019-12-31',7,12999),
(6068202189,'Włocławek','Kujawsko-pomorskie','Toyota Yaris II',2008,110000,'Benzyna',1298,17600,'PLN','2019-12-31',21,16900),
(6067206317,'Łódź','Łódzkie','Toyota Yaris II',2010,167938,'Diesel',1364,13999,'PLN','2019-12-31',31,13900),
(6069421596,'Katowice','Śląskie','Toyota Yaris II',2008,214548,'Benzyna+LPG',1298,12000,'PLN','2019-12-31',31,12000),
(6068568066,'Katowice','Śląskie','Toyota Yaris II',2007,38000,'Benzyna',1298,19300,'PLN','2019-12-31',12,18500);
"""