SQL с PostgreSQL для инженеров Node.js

Думайте о SQL (языке структурированных запросов) как о задаче вопросов базе данных (сколько, что это за и т. Д.)

Эта статья будет дампом мозгов о том, как использовать систему управления реляционными базами данных PostgreSQL (СУБД).

Основное внимание будет уделено ключевым и продвинутым концепциям стандартного языка SQL и его использованию в PostgreSQL.

Мы будем использовать PgAdmin в качестве панели управления для выполнения SQL-запросов. Это точно такие же запросы, которые вы будете выполнять в своих приложениях на Node.js (с помощью модуля объектно-реляционного сопоставления [ORM}, такого как TypeORM для поклонников TypeScript).

Установка PostgreSQL (PG) в Ubuntu

sudo apt install -y postgresql postgresql-contrib
# change the terminal user to postgres user (created when installing PG):
sudo -i -u postgres
# once logged as postgres user:
psql
 
# once in the PG CLI, type “help” or “\q” to quit
# OR access PG CLI without switching terminal user
sudo -u postgres psql
# create password for default postgres user, once in PG CLI:
ALTER USER postgres PASSWORD ‘myPassword’;

Вы также можете запустить официальный образ PostgreSQL Docker и подключиться к нему с вашего хост-компьютера независимо от вашей операционной системы.

Установка pgAdmin в ubuntu

wget — quiet -O — https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
echo “deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main” |sudo tee /etc/apt/sources.list.d/pgdg.list
sudo apt update
sudo apt install pgadmin4 pgadmin4-apache2
# During installation, you’re asked to configure initial user 
account. Provide email address.
# by default: postgres@localhost
# enter admin password
# verify apache is running
systemctl status apache2
# if using UFW (Ubuntu Firewall)
sudo ufw allow http
sudo ufw allow https
# execute pgadmin in Ubuntu program launcher
# it will open the browser
# you will be prompted to set a password for accessing pgadmin dashboard
# restart computer (or logout) (not necessary)

Добавить подключение к локальному PG в pgadmin

# click on add a new server
# name that server (arbitrary name)
# in connection tab, enter address of server (127.0.0.1 for local instance) 
# (if running the PG Docker image, make sure the running container ports are exposed to your host system - read the doc)
# enter username and password of a database user
# save
# that connection should appear on the left under server list

Добавить новую базу данных в pgadmin

Щелкните правой кнопкой мыши «Базы данных» / создать / базу данных.

Восстановление базы данных в pgadmin

  • вы можете восстановить базу данных из файла .tar
  • из существующей базы данных / щелчок правой кнопкой мыши / восстановление
  • указать путь к файлу .tar
  • в параметрах восстановления / выберите предварительные данные, данные, пост-данные
  • нажмите на восстановление

Запрос базы данных в pgadmin

  • выберите базу данных
  • Инструмент правого щелчка / запроса ИЛИ меню "Инструменты" в заголовке
  • вы можете увидеть существующие таблицы:
    ‹DB_NAME› / Schemas / public / Tables
  • у вас есть доступ к истории запросов и вы можете копировать запросы прямо в редактор
  • вы можете экспортировать результат запросов как csv
  • у вас есть доступ к документации для pgadmin и postgresql через меню справки в заголовке
  • введите запрос в текстовой области и нажмите F5 или символ воспроизведения, чтобы выполнить его

Оператор SELECT

  • получить информацию из таблицы
  • можно комбинировать с другими операторами в более сложных запросах

СИНТАКСИС:

SELECT <column_name> FROM <table_name>;
# same as:
select <column_name> from <table_name>;
# SQL is case insenitive as far as commands
  • точка с запятой не обязательна в PG или pgadmin (добавлено автоматически)
    , но может помочь для читабельности и перекрестной совместимости РСУБД запросов.
  • PG сначала смотрит на запрашиваемую таблицу, а не на какой столбец
  • Чтобы выбрать несколько столбцов, разделите их запятой («,»)
    (порядок имен столбцов не имеет значения для PG, однако pgadmin отобразит результаты в порядке запроса)
SELECT c1, c2 FROM mytable;

- чтобы выбрать все столбцы в таблице, используйте *

SELECT * FROM mytable;

Запросы всего = ›ПЛОХАЯ ПРАКТИКА, потому что увеличивает трафик между сервером базы данных и приложением. Это замедляет получение результатов. Делайте это только в тестовых / демонстрационных целях, а не в продакшене.

  • В pgadmin, чтобы увидеть все столбцы в таблице
    выберите таблицу / столбцы

ВЫБЕРИТЕ ДИСКТИНКТ

  • столбец в таблице может содержать повторяющиеся значения
  • чтобы перечислить уникальные / уникальные значения, используйте ключевое слово DISTINCT
  • DISTINCT оперирует столбцом

СИНТАКСИС:

SELECT DISTINCT col_name FROM table
# also works with parentheses
SELECT DISTINCT(col_name) FROM table
# Answers the question what are the unique values in col_name ?
Example:
SELECT DISTINCT rental_rate FROM film;
 
# answers “how many rental rates are there in the film column ?” or “what are the rental rates ?”

PG выполняет запросы наиболее оптимизированным способом, вы не обязательно получаете результаты каждый раз в одном и том же порядке (если вы не используете оператор SORT)

СЧИТАТЬ

  • Функция COUNT возвращает количество входных строк, соответствующих определенному условию запроса.
  • вы можете применить COUNT к определенному столбцу или ко всем столбцам, и результат должен быть таким же, потому что он просто подсчитывает количество возвращенных строк

СИНТАКСИС:

SELECT COUNT(name) from table;
SELECT COUNT(*) from table;
  • COUNT требует скобок, потому что это функция, выполняющая что-то
  • указание имени столбца может помочь понять вопрос, на который вы пытаетесь ответить
  • COUNT более полезно в сочетании с такими операторами, как DISTINCT.
SELECT COUNT(DISTINCT color_gradient) FROM color;
# you are executing a count on the result of DISTINCT color_gradient (how many different color gradients ?)
SELECT COUNT(DISTINCT amount) FROM payment;
# you are executing a count on the result of DISTINCT amount (how many different amounts ?)

ВЫБЕРИТЕ ГДЕ

  • Оператор WHERE позволяет указать условия для столбцов, которые должны быть возвращены,
  • Обычно используется с оператором SELECT (но не только)

СИНТАКСИС:

SELECT col1, col2
FROM table1
WHERE <conditions>;
  • Оператор WHERE появляется сразу после оператора FROM
  • условия используются для фильтрации строк, возвращаемых оператором SELECT
  • PG предоставляет стандартные операторы для выполнения условий:

- - - - - - - - -
операторы сравнения
- - - - - - - - -

сравнить значение столбца с чем-то

= equal
> greater than
< less than
>= greater than or equal to 
<= less than or equal to
<> / != not equal to (two options)

- - - - - - - - -
логические операторы
- - - - - - - - -

объединить несколько операторов сравнения

AND
OR
NOT

PG использует ОДИНАРНЫЕ ЦИТАТЫ для строк.
Конечно, важно использование заглавных букв внутри кавычек.

SELECT name;choice 
FROM table
WHERE name=’Florian’ AND choice=’red’;
SELECT * FROM film
WHERE rental_rate > 1.99
  AND replacement_cost >= 19.99
  AND rating = ‘R’;
  • нет необходимости повторять оператор WHERE для каждого ключевого слова AND
SELECT COUNT(*) FROM film
WHERE rental_rate > 4
AND replacement_cost >= 19.99
AND rating = ‘R’;
SELECT COUNT(*) FROM film
WHERE rating = ‘PG-13’ OR rating = ‘R’;
SELECT COUNT(*) FROM film
WHERE rating != ‘R’;

СОРТИРОВАТЬ ПО

Позволяет сортировать строки в зависимости от типа данных столбца в возрастающем или убывающем порядке.

  • алфавитный порядок для столбцов на основе строк
  • числовой порядок для числовых столбцов

    СИНТАКСИС
SELECT col1, col2
FROM table
ORDER BY col1,col2 <ASC | DESC>
  • ORDER BY обычно появляется ближе к концу запроса, так как вы хотите сначала выбрать и отфильтровать перед окончательной сортировкой
  • По умолчанию выполняется сортировка ASCendingly (от наименьшего к наибольшему), если вы опускаете тип сортировки.
  • можно использовать ORDER BY для нескольких столбцов
    это имеет смысл, когда в одном столбце есть повторяющиеся записи
— — — — — — — — — — — — — — — — — — — — — — — -
|     company     |    name    |   sales      |
 — — — — — — — — — — — — — — — — — — — — — — — — -
|     Apple       |   Florian  |   987654     |
 — — — — — — — — — — — — — — — — — — — — — — — — -
|     Apple       |    Malua   |    352468    |
 — — — — — — — — — — — — — — — — — — — — — — — — -
|     Aveni       |     Jeqn   |     2056     |
 — — — — — — — — — — — — — — — — — — — — — — — — -
|     Zenika      |     Toto   |    100000    |
 — — — — — — — — — — — — — — — — — — — — — — — — -
|     Aveni       |     Titi   |    5346      |
— — — — — — — — — — — — — — — — — — — — — — — — -
# running the following query on the above table
SELECT company, name
FROM table
ORDER BY company,sales;
# first sort = alpha order on company column
# second sort = numer order (ASC) on sales column
  • можно указать для каждого столбца вид сортировки:
ORDER BY company DESC,sales ASC;
  • ORDER BY идет после команды WHERE
  • вы можете упорядочить по столбцу, который вы не выбираете / не извлекаете, но это создает путаницу
    если вы сортируете по столбцу, обычно его извлекают, чтобы увидеть сортировку

LIMIT

  • позволяет ограничить количество строк, возвращаемых при запросе таблицы
  • полезно получить частичные данные, чтобы увидеть макет таблицы
  • полезно в сочетании с ORDER BY
  • LIMIT - это последняя команда, которую нужно выполнить
# answers “what were the 5 most recent paymentswhere there was a monetary transaction ?” :
SELECT * FROM payment
WHERE amount != 0.00
ORDER BY payment_date DESC
LIMIT 5;
# to see the layout of the payment table:
SELECT * FROM payment
LIMIT 1;
# "what were the id’s of the first customers who created a payment ?" :
SELECT customer_id FROM payment
ORDER BY payment_date ASC
LIMIT 10;
# "What are the 5 shortest movies in length ?" :
SELECT title,length FROM film
ORDER BY length ASC
LIMIT 5;

МЕЖДУ

  • Оператор BETWEEN, используемый для сопоставления значения с диапазоном значений
  • он включает границы,
    эквивалентные:
WHERE value >= <low_boundary> AND value <= <high_boundary>;

СИНТАКСИС:

WHERE value BETWEEN <low> AND <high>;

НЕ МЕЖДУ

value NOT BETWEEB <low> AND <high>
  • для получения строк, в которых значение исключено, значение из диапазона значений
    эквивалентное:
WHERE value < <low> AND value > <high>
  • Оператор BETWEEn может использоваться с датами в стандартном формате ISO 8601 (гггг-мм-дд):
date BETWEEN ‘2020–03–16’ AND ‘2020–06–13’;
  • при использовании оператора BETWEEN с датами, которые содержат временную метку, обратите внимание на использование операторов сравнения BETWEEN vs `‹ = `или` ›=`, потому что временные метки начинаются с 0:00, если вы хотите инклюзивность или эксклюзивность около 0:00 AM
SELECT COUNT(*) FROM payment
WHERE amount NOT BETWEEN 8 AND 9;
SELECT * FROM payment
WHERE payment_date BETWEEN ‘2007–02–01’ AND ‘2007–02–15’;
# will retrieve everything up until 2007–02–15 0:00
# does NOT go to the 24:00 mark
# Using the BETWEEN operator will stop at the beginning of the upper boundary day (0:00 AM); not the end of the day (24:00 PM).
# So, results during 2007–02–15 will not be displayed.

Чтобы не усложнять, при использовании BETWEEN с датами ISO (проверьте документацию)

  • всегда указывайте следующую дату как верхнюю границу, чтобы получать результаты до предыдущего дня включительно

IN

  • Оператор IN полезен для проверки того, включено ли значение в список из нескольких опций.

СИНТАКСИС

WHERE value IN (opt1,opt2)

Примеры:

SELECT color FROM table
WHERE color IN (‘red’, ‘blue’, ‘green’); // implicit OR statement color = ‘red’ OR color = ‘blue’:
SELECT color FROM table
WHERE color NOT IN (‘red’, ‘blue’, ‘green’);
SELECT * FROM payment
WHERE amount IN (0.99, 1.98, 1.99)
ORDER BY amount;
SELECT * FROM customer
WHERE first_name IN (‘John’, ‘Florian’, ‘Robert’);
SELECT * FROM customer
WHERE first_name LIKE ‘J%’ ;
SELECT * FROM customer
WHERE first_name ILIKE ‘J%’ AND last_name ILIKE ‘s%’ ;

LIKE и ILIKE (сопоставление с образцом)

  • Оператор LIKE позволяет выполнять сопоставление шаблонов со строковыми данными с использованием подстановочных знаков.
# percent (%) matches any sequence of characters
 
# underscore (_) matches any single character
 
# all names starting by capital A
WHERE name LIKE ‘A%’;
 
# all names ending with lowercqse a
WHERE name LIKE ‘%a’;
 
# LIKE is case sensitive
  • ILIKE не чувствителен к регистру
# Use _ as a wild card for a single character
WHERE title LIKE ‘Mission Impossible _’:
# use multiple underscores to match a specific number of single characters
WHERE version LIKE ‘#__’;
# combining pattern matching operators
# matches Terrence, Perry, Berringer, Merlot, Cerlock :
WHERE name LIKE ‘_er%’;
 
# PG supports full regex, check the docs

Примеры:

# how many payment transactions where greater than $5 ?
SELECT COUNT(amount)
FROM payment
WHERE amount > 5;
# How many actors have a first name that starts with letter P ?
SELECT COUNT(*)
FROM actor
WHERE first_name LIKE ‘P%’
# How many districts are your customers from ?
SELECT COUNT(DISTINCT district)
FROM address;
# List the districts of your customers
SELECT DISTINCT district
FROM address;
# How many films have a rating of R and a replacement cost beteen $5 and $15 ?
SELECT COUNT(*)
FROM film
WHERE rating = ‘R’
AND replacement_cost BETWEEN 5 AND 15;
# How many films have the word “Truman” somewhere in the title?
SELECT COUNT(*)
FROM film
WHERE title LIKE ‘%Truman%’;

Агрегатные функции

SQL предоставляет множество агрегатных функций

идея состоит в том, чтобы взять несколько входов и вернуть один выход

общие агрегатные функции:

AVG() — returns average value
 COUNT() — returns the number of values
 MAX() — returns maximum value
 MIN() — returns minimum value
 SUM() — returns sum of all values

вышеуказанные функции применяются к одному столбцу, что имеет смысл

  • агрегатные функции используются в предложениях SELECT или HAVING.
  • AVG () возвращает значение с плавающей запятой с множеством десятичных знаков. Используйте ROUND (), чтобы указать точность после десятичной дроби
  • COUNT () просто возвращает количество строк, поэтому вы обычно просто используете COUNT (*)
SELECT MIN(replacement_cost) FROM film;
SELECT MAX(replacement_cost) FROM film;
SELECT MIN(replacement_cost), MAX(replacement_cost) FROM film;
SELECT ROUND(AVG(replacement_cost), 2) // precision of 2 decimals
FROM film;
SELECT SUM(replacement_cost)
FROM film;

ГРУППА ПО

  • позволяет агрегировать столбцы по определенной категории
____________________________
|    category   |   data   |
____________________________
|        A      |   152    |
____________________________
|        A      |   486    |
____________________________
|        B      |   749    |
____________________________
|        B      |   384    |
____________________________
|        C      |   511    |
____________________________
  • вам нужно выбрать столбец, содержащий категориальные данные, чтобы использовать GROUP BY (чтобы результаты были понятны)
  • категориальные столбцы не непрерывны
    , они могут быть числовыми, но обрабатываться как категория (класс 1, класс 2, класс 3). В приведенной выше таблице у вас есть класс A, класс B и класс C. В этом контексте класс является синонимом категории.

    SYNTAX
SELECT category_col, <AGG_FUNC>(data_col)
FROM table
WHERE category-col != ‘A’
GROUP BY category-col;
  • GROUP BY должна располагаться сразу после оператора FROM или WHERE.

В операторе SELECT столбцы должны:

  • вызвать на них агрегатную функцию
  • быть в звонке GROUP BY

Для ясности: если вы ВЫБИРАЕТЕ столбец, но не применяете к нему агрегатную функцию, он ДОЛЖЕН появиться в GROUP BY:

SELECT company,division, SUM(sales)
FROM finance_table
# need to include campany and division columns because not used in aggregate function:
GROUP BY company,division;
# returns the total sum of sales per division per company
  • Операторы WHERE не должны ссылаться на результат агрегирования. Используйте предложение HAVING для фильтрации результатов агрегирования
SELECT company,division, SUM(sales)
FROM finance_table
# here you filter the division column before grouping by:
WHERE division IN (‘marketing’,’transport’)
GROUP BY company,division;
  • Если вы хотите отсортировать результаты на основе агрегата, обязательно укажите всю функцию:
    то, что вы ORDER BY, должно существовать в предложении SELECT
SELECT company, SUM(sales)
FROM finance_table
GROUP BY company
ORDER BY SUM(sales);
SELECT customer_id
FROM payment
GROUP BY customer_id
ORDER BY customer_id;

Примеры:

# What is the total amount spent per customer ?
SELECT customer_id, SUM(amount)
FROM payment
GROUP BY customer_id
ORDER BY SUM(amount) DESC;
# How many transactions per customer ?
SELECT customer_id, COUNT(amount)
FROM payment
GROUP BY customer_id
ORDER BY COUNT(amount) DESC;
# What is the total amount spent per staff per customer ?
SELECT customer_id,staff_id, SUM(amount)
FROM payment
GROUP BY staff_id,customer_id;
# usually, you are going to GROUP BY in the same order than you SELECT (order in GROUP BY matters):
SELECT staff_id,customer_id, SUM(amount)
FROM payment
GROUP BY staff_id,customer_id
ORDER BY staff_id, SUM(amount) DESC;
# To GROUP BY by a timestamp, you must first convert it to a date (removes the time part, to have large enough classes to group by)
 
SELECT DATE(payment_date), SUM(amount)
FROM payment
GROUP BY DATE(payment_date)
ORDER BY SUM(amount)
# How many payment did each staff member handled ?
SELECT staff_id, COUNT(amount)
FROM payment
GROUP BY staff_id;
# What is the average replacement cost per MPAA rating ?
SELECT rating,ROUND(AVG(replacement_cost), 2)
FROM film
GROUP BY rating;
# What are the top 5customer ids of the top 5 customers by total spend ?
SELECT customer_id, SUM(amount)
FROM payment
GROUP BY customer_id
ORDER BY SUM(amount) DESC
LIMIT 5;

ИМЕЮЩИЕ

  • позволяет фильтровать после агрегирования
  • вы не можете использовать WHERE для фильтрации агрегированных результатов, потому что они появляются после выполнения WHERE
  • HAVING позволяет нам фильтровать совокупные результаты вместе с GROUP BY
SELECT company, SUM(sales)
FROM finance_table
WHERE company != ‘Google’
GROUP BY company
HAVING SUM(sales) > 1000;
SELECT customer_id, SUM(amount)
FROM payment
GROUP BY customer_id
HAVING SUM(amount) > 100;
  • вы должны использовать агрегатную функцию в HAVING, а не только имя столбца

Примеры:

# Number of cistomers per store where greater than 300 ?
SELECT store_id, COUNT(customer_id) FROM customer
GROUP BY store_id
HAVING COUNT(customer_id) > 300
# What are customers with 40 payment or more ?
SELECT customer_id, COUNT(payment_id)
FROM payment
GROUP BY customer_id
HAVING COUNT(payment_id) >= 40;
# What are the customer ids who have spent more than $100 in payment transactions with staff id member 2 ?
SELECT staff_id, customer_id, SUM(amount)
FROM payment
WHERE staff_id = 2
GROUP BY staff_id, customer_id
HAVING SUM(amount) > 100;
# Return the customer IDs of customers who have spent at least $110 with the staff member who has an ID of 2.
SELECT customer_id, SUM(amount)
FROM payment
WHERE staff_id = 2
GROUP BY customer_id
HAVING SUM(amount) >= 110;
# How many films begin with the letter J?
SELECT count(*)
FROM film
WHERE title LIKE ‘J%’;
# What customer has the highest customer ID number whose name starts with an ‘E’ and has an address ID lower than 500?
SELECT first_name, last_name
FROM customer
WHERE first_name LIKE ‘E%’
AND address_id < 500
ORDER BY customer_id DESC
LIMIT 1;

ПРИСОЕДИНЯЕТСЯ

  • объединить информацию из нескольких таблиц

AS

  • позволяют нам создать псевдоним для столбца или результата

СИНТАКСИС:

SELECT column AS new_name
FROM table;
SELECT SUM(column) AS new_name
FROM table;
  • помогает для читабельности вывода
SELECT SUM(amount) AS net_revenue
FROM payment;
  • Оператор AS выполняется в КОНЦЕ запроса
    . Вы НЕ МОЖЕТЕ использовать псевдоним внутри оператора WHERE или HAVING:
SELECT customer_id, SUM(amount) AS total_spent
FROM payment
GROUP BY customer_id
HAVING SUM(amount) > 100;
# you **cannot** use the alias in a conditional clause
# AS creates aliases for the OUTPUT RESULTS
  • Псевдоним, созданный AS в операторе FROM, можно повторно использовать в запросе (см. Раздел подзапроса).

ВНУТРЕННЕЕ СОЕДИНЕНИЕ (симметричное)

  • это JOIN по умолчанию
  • JOINs позволяют нам объединять несколько таблиц вместе
  • различные типы JOIN, чтобы решить, как работать с данными, присутствующими только в одной из соединенных таблиц
_________________________
 REGISTRATIONS LOGINS
_________________________
-----------------------------------------
|  reg_id  |  name  |  log_id |  name   |
-----------------------------------------
|     1    | Andrew |    1    |  Xavier |
-----------------------------------------
|     2    |  Bob   |    2    |  Andrew |
-----------------------------------------
|     3    | Carl   |    3    |  Yoland |
-----------------------------------------
|     4    | David  |    4    |   Bob   |
-----------------------------------------
  • INNER JOIN приведет к набору записей, соответствующих ОБЕИМ таблицам (выше ttable)

СИНТАКСИС:

SELECT * 
FROM tableA
INNER JOIN tableB
ON tableA.col_match = tableB.col_match;
  • ВНУТРЕННИЕ СОЕДИНЕНИЯ являются симметричными, поскольку вы возвращаете строки, существующие в обеих таблицах, в одном столбце (то есть в обеих таблицах).
SELECT *
FROM registrations
INNER JOIN logins
ON registrations.name = logins.name;
  • вернет все столбцы совпадающих строк в обеих таблицах
SELECT reg_if,logins.name,log_id
FROM registrations
INNER JOIN logins
ON registrations.name = logins.name;
  • порядок таблиц не имеет значения в qINNER JOIN
...
FROM registrations
INNER JOIN logins
...
# same as :
...
FROM logins
INNER JOIN registrations
...
  • JOIN без INNER будет рассматриваться PostgreSQL как INNER JOIN.
  • При выборе столбцов, если они появляются только в одной таблице, вам не нужно указывать таблицу (`tableA.col_1`)
SELECT payment_id, payment.customer_id, first_name
FROM payment
INNER JOIN customer
ON payment.customer_id = customer.customer_id
  • если столбец отображается в обеих таблицах, необходимо указать имя таблицы.

ВНЕШНЕЕ СОЕДИНЕНИЕ

  • позволяет работать со значениями, присутствующими только в одной из объединяемых таблиц

ПОЛНОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ (симметричное)

  • захватывает все в обеих таблицах и заполняет нулевыми значениями, если в другой таблице нет совпадений

СИНТАКСИС:

SELECT * FROM tableA
 FULL OUTER JOIN tableB
 ON tableA.col_match = tableB.col_match;
# Postgres will grab registrations table then look for matches in logins tables
# will place matches on the same rows like an INNER JOIN
# then will fill in null values no match in other table
 
_______________________________________
 reg_id     name     log_id      name
_______________________________________
     1     Andrea       2       Andrew
_______________________________________ 
     2       Bob        4         Bob
_______________________________________
     3     Charlie   [ null ]  [ null ]
_______________________________________
     4      David    [ null ]  [ null ]
_______________________________________
  [ null ] [ null ]      1      Xavier
_______________________________________
  [ null ] [ null ]      3      Yolanda
_______________________________________

ПОЛНОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ с ГДЕ (симметричное)

  • уточнение ПОЛНОГО ВНЕШНЕГО СОЕДИНЕНИЯ с ГДЕ
  • получить строки, уникальные для любой таблицы (не найдены в обеих / найдены только в одной) = противоположность ВНУТРЕННЕГО СОЕДИНЕНИЯ

СИНТАКСИС:

SELECT * FROM tableA
 FULL OUTER JOIN tableB
 ON tableA.col_match = tableB.col_match
 WHERE tableA.id_col IS null 
 OR tableB.id_col IS null;
# will only show results that are unique to either registrations or logins no more values that appear in both:
 
 SELECT * FROM registrations
 FULL OUTER JOIN logins
 ON registrations.name = logins.name
 WHERE registrations.reg_id IS null 
 OR logins.log_id IS null;
# check for customers that don’t have transactions and transactions that don’t have customer associated to:
SELECT *
FROM customer
FULL OUTER JOIN payment
ON customer.customer_id = payment.customer_id
WHERE customer.customer_id IS null
OR payment.payment_id IS null

LEFT OUTER JOIN / LEFT JOIN

  • приводит к набору записей, которые находятся в левой таблице
    , если нет совпадения с правой таблицей, результаты равны нулю

СИНТАКСИС:

SELECT * 
 FROM tableA
 LEFT OUTER JOIN tanleB // same as LEFT JOIN tanleB in SQL syntax 
 ON tableA.col_match = tableB.col_match
  • Несимметричный = порядок таблиц имеет значение
  • Левая таблица - это первая таблица, на которую ссылается оператор FROM.
  • результатом будут все значения из левой таблицы (значения исключительно в левой таблице и значения в обеих таблицах)
  • значения, исключительные для левой таблицы, будут иметь столбцы правой таблицы, заполненные нулем
SELECT *
 FROM registrations
 LEFT OUTER JOIN logins
 ON registrations.name = logins.name;
_______________________________________
   reg_id     name    log_id      name
_______________________________________
     1       Andrew     2        Andrew
_______________________________________
     2        Bob       4          Bob
_______________________________________
     3      Charlie  [ null ]   [ null ]
_______________________________________
     4       David   [ null ]   [ null ]
_______________________________________

LEFT OUTER JOIN / LEFT JOIN с WHERE

  • чтобы получить строки, исключительные для левой таблицы (нет совпадений в правой таблице)
SELECT * 
 FROM tableA
 LEFT OUTER JOIN tanleB 
 ON tableA.col_match = tableB.col_match
 WHERE tableB.id_col IS null;
SELECT *
 FROM registrations
 LEFT OUTER JOIN logins
 ON registrations.name = logins.name
 WHERE logins.log_id IS null;
_____________________________________________
   reg_id     name      log_id      name
_____________________________________________
      3      Charlie   [ null ]    [ null ]
_____________________________________________
      4       David    [ null ]    [ null ]
_____________________________________________
SELECT film.film_id, title, inventory_id, store_id
FROM film
LEFT OUTER JOIN inventory
ON film.film_id = inventory.film_id;
# Which films are not in inventory nor in stor ?
SELECT film.film_id, title, inventory_id, store_id
FROM film
LEFT OUTER JOIN inventory
ON film.film_id = inventory.film_id
WHERE inventory.film_id IS NULL;

ПРАВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ / ПРАВОЕ СОЕДИНЕНИЕ

  • то же самое, что LEFT JOIN (/ LEFT OUTER JOIN), за исключением того, что таблицы переключаются
  • строго то же самое, что и переключение порядка таблиц в LEFT OUTER JOIN

СИНТАКСИС:

SELECT *
FROM tableA
RIGHT OUTER JOIN tableB
ON tableA.col_match = tableB.col_match;
  • вы берете все в таблице оператора RIGHT OUTER JOIN

Цель состоит в том, чтобы сохранить тот же порядок таблиц в запросе, но иметь механизмы для захвата всего слева или справа (диаграмма Венна)

RIGHT OUTER JOIN / RIGHT JOIN с WHERE

  • чтобы получить значения, исключительные для правой таблицы:
SELECT *
FROM tableA
RIGHT OUTER JOIN tableB
ON tableA.col_match = tableB.col_match
WHERE tableA.id_col IS null;
  • Вы должны иметь возможность получить тот же результат с LEFT JOIN или RIGHT JOIN, переключая порядок таблиц

СОЮЗ

  • Оператор UNION, используемый для объединения набора результатов из двух или более операторов SELECT
  • служит для объединения двух результатов вместе

СИНТАКСИС:

SELECT col_name(s) FROM table1
UNION
SELECT col_name(s) FROM table2;
  • SELECT, которые объединены в UNION, должен быть логичным и каким-то образом совпадать, чтобы Postgres мог складывать результаты друг над другом.
____________________
    sales2021_Q1     
____________________
|  NAME   |  AMOUNT |
____________________
|  David  |   1550  |
____________________
|  Bruna  |   1050  |
____________________
___________________
    sales2021_Q2
___________________
|  NAME   | AMOUNT |
___________________
|  David  |  2050  |
___________________
|  Bruna  |  1550  |
___________________
SELECT * FROM sales2021_Q1
UNION
SELECT * FROM sales2021_Q2;
# displays:
 
_______________
 NAME  | AMOUNT 
_______________
 David | 1550 
_______________
 Bruna | 1050 
_______________
 David | 2050
_______________
 Bruna | 1550
_______________
# what are the emails of the customers who live in California ?
SELECT district, email
FROM customer
INNER JOIN address
ON customer.address_id = address.address_id
WHERE address.district = ‘California’;
# List all movies Nick Wahlberg has been in:
SELECT film.title, actor.first_name, actor.last_name from film_actor
INNER JOIN film
ON film_actor.film_id = film.film_id
INNER JOIN actor
ON film_actor.actor_id = actor.actor_id
WHERE actor.first_name = ‘Nick’ AND actor.last_name = ‘Wahlberg’;
# The second INNER JOIN is on the results of the first INNER JOIN

РАСШИРЕННЫЕ ТЕМЫ SQL

Метки времени и ЭКСТРАКТ

  • более полезно при создании баз данных, чем их запросы
  • PG может хранить информацию о дате и времени:
TIME — contains only time
DATE — contains only date
TIMESTAMP — contains date and time
TIMESTAMPZ — contains date, time and timezone
  • при разработке таблицы и базы данных и выборе типа данных времени следует тщательно продумать (прочтите документацию).
  • в зависимости от варианта использования вам может потребоваться или не потребоваться полный уровень TIMESTAMPZ
  • Вы всегда можете восстановить историческую информацию, но не можете ее добавить
  • думайте о долгосрочной перспективе при выборе данных, вы не можете позже добавить временные данные, которые вы изначально не записывали
  • Этот вид данных наиболее полезен при работе с CRUD-операциями.
SHOW ALL
# Show the values of all configuration parameters, with descriptions.
 
SHOW TIMEZONE
# show the timezone runtime parameter of the computer on which PG is running
SELECT NOW()
# returns a timestamp with time zone (GMT standandard-
 
SELECT TIMEOFDAY()
# returns timestamp as a human friendly string
 
SELECT CURRENT_TIME
# returns a time with time zone
 
SELECT CURRENT_DATE
# returns only the date

ИЗВЛЕЧЕНИЕ ИНФОРМАЦИИ О ВРЕМЕНИ И ДАТЕ

ИЗВЛЕКАТЬ( )

  • позволяет получить подкомпонент значения даты
  • вы можете извлечь:
YEAR
 MONTH
 DAY
 WEEK
 QUARTER

СИНТАКСИС:

EXTRACT(YEAR FROM date_col)

Примеры:

SELECT EXTRACT(YEAR FROM payment_date) AS payment_year
FROM payment;
SELECT EXTRACT(MONTH FROM payment_date) AS payment_month
FROM payment;
SELECT EXTRACT(QUARTER FROM payment_date) AS payment_quarter
FROM payment;

ВОЗРАСТ( )

вычисляет и возвращает текущий возраст с учетом отметки времени

СИНТАКСИС:

AGE(date_col)
# returns 
 20 years 1 mon 5 days 01:34:13.003423
SELECT AGE(payment_date)
FROM payment;

TO_CHAR ()

  • общая функция для преобразования типов данных (не только типов даты) в текст
  • полезно для формирования метки времени
  • СИНТАКСИС:
TO_CHAR(date_col, ‘MM-dd-YYYY’)
  • посмотрите документы PG (функции форматирования типов данных) для шаблонов для форматирования вывода


  • Разделение между частями даты произвольное.
TO_CHAR(date_col, ‘MM-dd-YYYY’)
 TO_CHAR(date_col, ‘MMddYYYY’)
 TO_CHAR(date_col, ‘MM/dd/YYYY’)
 TO_CHAR(date_col, ‘MONTH YYYY’)

Примеры:

# During which months did payments occur (show full name of month) ?
 
SELECT DISTINCT TO_CHAR(payment_date, ‘MONTH’)
FROM payment;
# How many payments occurred on a Monday ?
SELECT COUNT(*)
FROM payment
WHERE EXTRACT(
 ISODOW FROM payment_date
) = 1;

МАТЕМАТИЧЕСКИЕ ФУНКЦИИ И ОПЕРАТОР

  • Посмотрите документы:

Https://www.postgresql.org/docs/12/functions-math.html

SELECT ROUND(rental_rate/replacement_cost, 4) * 100 AS percent_cost
FROM film;

СТРОЧНЫЕ ФУНКЦИИ И ОПЕРАЦИИ

  • PG предоставляет множество строковых функций и операторов, которые позволяют редактировать / комбинировать / изменять столбцы текстовых данных.
  • посмотрите документы
    https://www.postgresql.org/docs/12/functions-string.html
SELECT length(first_name)
FROM customer;
# use alias to give name to result column
SELECT first_name || ‘ ‘ || UPPER(last_name) AS full_name
FROM customer;
# Generate email from first letter of firstname and lastname:
SELECT LOWER(LEFT(first_name, 1)) || LOWER(last_name) || ‘@gmail.com’ 
AS customer_email
FROM customer:

ПОД ЗАПРОС

  • Подзапрос позволяет создавать сложные запросы, по сути выполняя запрос по результатам другого запроса.
  • Пример SYNTAX:
SELECT student,grade
FROM test_scores
WHERE grade > (
 SELECT AVG(grade)
 FROM test-scores
);
  • подзапрос запускается первым, потому что он заключен в круглые скобки и дает результат
  • вы можете использовать оператор IN вместе с подзапросом для проверки нескольких возвращенных результатов
    это можно сделать с помощью JOIN, но иногда проще использовать подзапрос
SELECT student,grade
 FROM test_scores
 WHERE student IN (
  SELECT student
  FROM honor_roll_table
 );
  • оператор EXISTS используется для проверки наличия строк в подзапросе
  • внутри функции EXISTS () передается подзапрос, чтобы проверить, возвращаются ли какие-либо строки с подзапросом
# returns true or false wether rows were returned
SELECT col_name
 FROM table_name
 WHERE EXISTS(
  SELECT COL_NAME
  FROM table_name
  WHERE condition
);
# List the films that have a rental rate higher than the average rental rate for all films:
SELECT title, rental_rate
FROM film
WHERE rental_rate > (
 SELECT AVG(rental_rate)
 FROM FILM
);
# List film names returned on the 29th May 20005:
SELECT film_id,title
FROM film
WHERE film.film_id IN(
 SELECT inventory.film_id
 FROM rental
 INNER JOIN inventory
 ON rental.inventory_id = inventory.inventory_id
 WHERE rental.return_date BETWEEN ‘2005–05–29’ AND ‘2005–05–30’
)
ORDER BY title;
# List customers who have at least one payment greater than $11:
SELECT first_name,last_name
FROM customer AS c
WHERE EXISTS(
 SELECT *
 FROM payment AS p
 WHERE p.customer_id = c.customer_id
 AND amount > 11
);

САМОПРИСОЕДИНЕНИЕ

  • запрос, в котором таблица присоединяется к самой себе
  • полезно для сравнения значений в столбце строк в одной и той же таблице
  • можно рассматривать как объединение двух копий одной и той же таблицы
    таблица не копируется, но SQL действует так, как если бы
  • Нет особого синтаксиса, кроме стандартного синтаксиса JOIN с одинаковой таблицей с обеих сторон
  • Необходимо использовать псевдонимы таблиц, чтобы не было двусмысленности
SELECT A.col,B.col
 FROM tableA AS A
 INNER JOIN tableA AS B
 ON A.some_col = B.other_col;
 
 
SELECT emp.name, report.name AS rep
FROM employees AS emp
INNER JOIN employees AS report
ON emp.emp_id = report.report_id;
# Find all the pairs of films that have the same length:
SELECT f1.title,f2.title,f1.length
FROM film AS f1
JOIN film AS f2
ON f1.film_id != f2.film_id // notice !=, otherwise will join row with itself
AND f1.length = f2.length
  • База данных может иметь несколько схем
  • таблицы, которые не входят в общедоступную схему, должны запрашиваться с использованием имени частной содержащей схемы:
SELECT * FROM private_schema.my_table

УПРАЖНЯТЬСЯ

# Produce a list of the total number of slots booked per facility in the month of September 2012. 
# Produce an output table consisting of facility id and slots, sorted by the number of slots.
SELECT B.facid,F.name,SUM(B.slots) AS booked_slots
 FROM cd.bookings AS B
 INNER JOIN cd.facilities AS F
 ON B.facid = F.facid
 WHERE B.starttime BETWEEN ‘2012–09–01’ AND ‘2012–10–1’
 GROUP BY B.facid,F.name
 ORDER BY SUM(B.slots);
# Produce a list of facilities with more than 1000 slots booked. 
# Produce an output table consisting of facility id and total slots, sorted by facility id.
SELECT facid,SUM(slots)
 FROM cd.bookings
 GROUP BY facid
 HAVING SUM(slots) > 1000
 ORDER BY facid;
# How can you produce a list of the start times for bookings for tennis courts, for the date ‘2012–09–21’? 
# Return a list of start time and facility name pairings, ordered by the time.
SELECT B.starttime, F.name
 FROM cd.bookings AS B
 INNER JOIN cd.facilities F
 ON B.facid = F.facid
 WHERE F.name LIKE ‘Tennis Court _’ /* or WHERE F.facid IN (0,1) */
 AND B.starttime BETWEEN ‘2012–09–21’ AND ‘2012–09–22’
 ORDER BY B.starttime;
# How can you produce a list of the start times for bookings by members named ‘David Farrell’?
SELECT B.starttime, (M.firstname || ‘ ‘ || M.surname) AS member_name
 FROM cd.bookings AS B
 INNER JOIN cd.members AS M
 ON B.memid = M.memid
 WHERE M.firstname = ‘David’ AND M.surname = ‘Farrell’;

СОЗДАНИЕ ДАННЫХ И ТАБЛИЦ

ТИПЫ ДАННЫХ

  • при создании таблицы необходимо выбрать типы столбцов в ней:
Boolean data types:
 True or False
 
Character data types:
 char, varchar and text
 
Numerice data types:
 integer and floating-point number
 
Temporal:
 date, time, timestamp and interval
  • другие виды:
UUID
 Universality Unique Identifiers
 
Array
 stores an array of strings, numbers, etc.
 
JSON
 
Hstore
 key-value pair
  • специальные типы, такие как:
network address
geometric data
etc.
  • в каждом из перечисленных выше типов данных есть еще более тонкие типы данных, прочтите документацию
  • при создании баз данных и таблиц необходимо тщательно продумать, какие типы данных следует использовать для хранения данных
    прочтите документацию PG об ограничениях конкретных типов данных
    https://www.postgresql.org /docs/9.5/datatype.html
  • поиск передовых методов о том, какие типы данных использовать для хранения определенных типов данных
    например, сохранять телефонные номера в виде текстовых данных (varchar)
  • планируйте долгосрочное хранение
    вы можете удалить исторические данные, но не добавлять данные, которые вы изначально не записывали.
    запишите дополнительную информацию, которая необходима в начале

ПЕРВИЧНЫЕ И ИНОСТРАННЫЕ КЛЮЧИ

  • ПЕРВИЧНЫЙ КЛЮЧ - это столбец или группа столбцов, которые используются для уникальной идентификации строки в таблице.
  • первичные ключи позволяют нам легко определить, какие столбцы следует использовать для объединения таблиц.
  • столбцы первичного ключа должны быть уникальными в каждой строке и отличаться от нуля
    первичным ключом может быть любой столбец, который соответствует этим стандартам
  • ИНОСТРАННЫЙ КЛЮЧ - это поле или группа полей в таблице, которые однозначно идентифицируют строку в другой таблице.
  • внешний ключ определяется в таблице, которая ссылается на первичный ключ другой таблицы
  • таблица, содержащая FK, называется СПРАВОЧНАЯ ТАБЛИЦА ИЛИ ДЕТСКАЯ ТАБЛИЦА.
  • таблица, на которую ссылается FK, называется СООТВЕТСТВУЮЩАЯ ТАБЛИЦА или РОДИТЕЛЬСКАЯ ТАБЛИЦА.
  • таблица может иметь несколько FK в зависимости от ее отношений с другими таблицами
  • PK и FK - хороший выбор столбцов для объединения таблиц
  • при создании таблиц и определении столбцов,
    вы можете использовать CONSTRAINTS для определения столбцов как PK или присоединения отношения FK к другой таблице
  • чтобы получить информацию о PK и FK в PostgreSQL, в PgAdmin:
look into the details of the tables and columns in the database explorer:
Schemas / <NAME_SCHEMA> (public as default choice) / Tables / <TABLE_NAME> / Constraints
 
 the golden key symbol represents the primary key for that table (<TABLE_NAME>_pkey)
 the dual silver key symbol represents foreign keys (which are constraints on that table) (<TABLE_NAME>_<COL_NAME>_fkey)
 
 to get more details on keys: 
 — select the FK in explorer and click on dependencies tab in header
 — select FK, right click / properties / columns 
 
 
 the tables in the “public” Schema represent public relationships
 you can query these table directly, no need to do “FROM public.<TABLE_NAME>”
 
 if tables are not in the public Schema, you need to specify the schema name to access the tables
 “FROM <SCHEMA_NAME>.<TABLE_NAME>”

ОГРАНИЧЕНИЯ

  • ограничения - это правила, применяемые к столбцам данных в таблице
    также могут использоваться для ограничения всего в таблице
  • используются для ПРЕДОТВРАЩЕНИЯ НЕДЕЙСТВИТЕЛЬНЫХ ДАННЫХ от ввода в БД
  • обеспечивает точность и надежность данных в БД
  • ограничения делятся на две основные категории:
    ограничения столбца:
    ограничивают данные в столбце, чтобы они соответствовали определенным условиям
    ограничения таблицы :
    применяется ко всей таблице, а не к отдельному столбцу
  • наиболее распространенные ОГРАНИЧЕНИЯ КОЛОНКИ:
NOT NULL constraint
 ensures that a column cannot have NULL value
 UNIQUE constraint
 ensures that all values in a column are different
 
PRIMARY Key
 uniquely identifies each row / record in a database table
 FOREIGN Key
 constrains data based on columns in other tables
 creates a relationship with another table
 
CHECK constraint
 ensures that all values in a column satisfy certain conditions
 
EXCLUSION constraint
 ensures that if any two rows are compared on the specified column or expression using the specified operator,not all of these comparisons will return TRUE
  • ОГРАНИЧЕНИЯ ТАБЛИЦЫ:
CHECK (condition)
 to check a condition when inserting or updating data
REFERENCES
 to constrain the value stored in the column that must exist in a column in another column
UNIQUE (column_list)
 forces the values stored in the columns listed inside the parentheses to be uniqque (within multiple columns)
PRIMARY KEY (column_list)
 allows you to define the primary key that consists of multiple columns

СОЗДАЙТЕ

  • Полный общий синтаксис:
CREATE TABLE <TABLE_NAME> (
 <COLUMN_NAME> <DATA_TYPE> <COLUMN_CONSTRAINT>,
 <COLUMN_NAME> <DATA_TYPE> <COLUMN_CONSTRAINT>,
 <TABLE_CONSTRAINT> <TABLE_CONSTRAINT>
 ) INHERITS <EXISTING_TABLE_NAME>;
  • ОБЩИЙ ПРОСТОЙ СИНТАКСИС:
CREATE TABLE <TABLE_NAME> (
 <COLUMN_NAME> <DATA_TYPE> <COLUMN_CONSTRAINT>,
 <COLUMN_NAME> <DATA_TYPE> <COLUMN_CONSTRAINT>,
 );
 
 
 CREATE TABLE players (
 player_id SERIAL PRIMARY KEY,
 AGE SMALLINT NOT NULL,
 );
  • SERIAL
    - в PostgreSQL последовательность - это особый вид объекта базы данных, который генерирует последовательность целых чисел
    - последовательность часто используется в качестве столбца первичного ключа в таблице
    - она ​​создает объект последовательности и установите следующее значение, сгенерированное последовательностью, в качестве значения по умолчанию для столбца
    - это идеально подходит для первичного ключа, потому что он автоматически регистрирует уникальные целочисленные записи для вас при вставке, когда вы вставляете больше данных в этот table, вам не нужно будет указывать уникальное значение для col_id самостоятельно
    - если строка позже будет перемещена, столбец с типом данных SERIAL НЕ будет настраиваться, что указывает на то, что строка была удалена из последовательности ( 1,2,4,6,7,8 - идентификаторы 3 и 5 удалены)
  • вы можете запустить запрос CREATE TABLE только один раз
CREATE TABLE account (
 user_id SERIAL PRIMARY KEY,
 username VARCHAR(50) UNIQUE NOT NULL,
 password VARCHAR(50) NOT NULL,
 email VARCHAR(250) UNIQUE NOT NULL,
 created_on TIMESTAMP NOT NULL,
 last_login TIMESTAMP
);
CREATE TABLE job (
 job_id SERIAL PRIMARY KEY,
 job_name VARCHAR(200) UNIQUE NOT NULL
);
  • при ссылке на внешние ключи в таблице используйте тип данных INTEGER вместо SERIAL
CREATE TABLE account_job (
 user_id INTEGER REFERENCES account(user_id),
 job_id INTEGER REFERENCES job(job_id),
 hired_date TIMESTAMP 
);

ВСТАВЛЯТЬ

  • позволяет добавлять строки в таблицу
  • общий синтаксис:
INSERT INTO <TABLE_NAME> (<COL_1>,<COL_2>,…)
 VALUES
 (<VALUR_1>, <VALUR_2>,…),
 (<VALUR_1>, <VALUR_2>,…),
 … ;
  • СИНТАКСИС для вставки значений из другой таблицы
INSERT INTO <TABLE_NAME> (<COL_1>,<COL_2>,…)
 SELECT <COL_1>,<COL_2>,…
 FROM <OHTER_TABLE>
 WHERE <CONDITION>;
  • вставленные значения строк должны совпадать с таблицей, включая ограничения
  • Столбцы SERIAL не нуждаются в значении.
INSERT INTO account (username,password,email, created_on)
VALUES
 (‘toto’, ‘passwordtoto’, ‘[email protected]’, CURRENT_TIMESTAMP),
 (‘titi’, ‘passwordtiti’, ‘[email protected]’, CURRENT_TIMESTAMP),
 (‘tutu’, ‘passwordtutu’, ‘[email protected]’, CURRENT_TIMESTAMP);
  • при вставке данных в таблицу с помощью FK вы должны убедиться, что значения существуют в ссылочных таблицах
  • вы не можете добавить user_id FK для пользователя, которого нет в таблице учетных записей, потому что он нарушает ограничение

ОБНОВИТЬ

  • ключевое слово UPDATE позволяет изменять значения столбцов в таблице
  • общий СИНТАКСИС
UPDATE <TABLE_NAME>
 SET <COL_1>=<VALUE_X>,
 <COL_2>=<VALUE_Y>,….
 WHERE <CONDITION>;
 
 
 UPDATE account
 SET last_login = CURRENT_TIMESTAMP
 WHERE last_login IS NULL;
  • чтобы сбросить все без условия WHERE, просто опустите его
  • установить на основе другого столбца:
UPDATE account
 SET last_login=created_on
  • с использованием значений другой таблицы (также известного как UPDATE join):
UPDATE tableA
 SET original_col = tableB.new_col
 FROM tableB
 WHERE tableA.id = tableB.id;
  • вернуть затронутые строки:
UPDATE account
 SET last_login = created_on
 RETURNING account_id,last_login;
 
 
 UPDATE account
 SET last_login = created_on
 RETURNING email,created_on,last_login; 
 
 UPDATE account_job
 SET hired_date = account.created_on
 FROM account
 WHERE account.user_id = account_job.user_id;

УДАЛИТЬ

  • используйте предложение DELETE для удаления строк из таблицы
  • СИНТАКСИС:
DELETE FROM <TABLE_NAME>
 WHERE row_id = 1;
  • вы можете удалять строки в зависимости от их присутствия в других таблицах (также известное как соединение DELETE)
DELETE FROM tableA
 USING tableB
 WHERE tableA.id = tableB.id;
# if there is a match, row will be deleted from tableA
  • вы можете удалить все строки из таблицы:
DELETE FROM <TABLE_NAME>;
  • вы можете добавить вызов RETURNING для возврата удаленных строк:
DELETE FROM <TABLE_NAME>
 RETURNING <COL_NAME>;
 
 
 DELETE FROM job
 WHERE job_name = ‘jobidon’
 RETURNING job_id,job_name;

ИЗМЕНИТЬ

  • предложение ALTER позволяет вносить изменения в существующую структуру таблицы, например
    - добавление, извлечение или переименование столбцов
    - изменение типа данных столбца
    - установка значений DEFAULT для столбца
    - добавить ограничения CHECK
    - переименовать таблицу
  • общий СИНТАКСИС:
ALTER TABLE <TABLE_NAME> <ACTION>;
  • добавление столбцов:
ALTER TABLE <TABLE_NAME>
 ADD COLUMN <COL_NAME> <TYPE>;
ALTER TABLE job
 ADD COLUMN totocol INTEGER;
  • удаление столбцов:
ALTER TABLE <TABLE_NAME>
 DROP COLUMN <COL_NAME>;
  • изменить ограничения существующего столбца:
ALTER TABLE <TABLE_NAME>
 ALTER COLUMN <COL_NAME>
 SET DEFAULT <VALUE>;
.. DROP DEFAULT;
 .. SET NOT NULL; 
 .. DROP NOT NULL; 
 .. ADD CONSTRAINT <CONSTRAINT_NAME>;
 etc…
  • переименование таблицы:
ALTER TABLE information
 RENAME TO new_info;
  • переименование столбца:
ALTER TABLE new_info
 RENAME COLUMN person TO people; 
 
 ALTER TABLE new_info
 ALTER COLUMN people DROP NOT NULL;
 
 INSERT INTO new_info(title)
 VALUES (‘mytile’)
 RETURNING *;

УРОНИТЬ

  • DROP позволяет полностью удалить столбец в таблице
  • в PostgreSQL это также автоматически удалит все его индексы и ограничения, связанные с столбцом
  • он не будет удалять столбцы, используемые в представлениях, триггерах или хранимых процедурах, без дополнительного предложения CASCADE
  • общий СИНТАКСИС:
ALTER TABLE <TABLE_NAME>
 DROP COLUMN <COL_NAME>;
# remove all dependencies
 
 ALTER TABLE <TABLE_NAME>
 DROP COLUMN <COL_NAME> CASCADE;
# check for existence to avoid error
ALTER TABLE <TABLE_NAME>
 DROP COLUMN IF EXISTS <COL_NAME>;
# drop multiple columns
ALTER TABLE <TABLE_NAME>
 DROP COLUMN <COL_1>,
 DROP COLUMN <COL_2>,
 DROP COLUMN <COL_3>;
 
 
ALTER TABLE new_info
DROP COLUMN IF EXISTS people
# will not return an error if the column does not exist, just a notice that the column does not exists

ЧЕК

  • позволяет создавать более индивидуальные ограничения, которые соответствуют определенному условию
  • например, убедитесь, что все вставленные целочисленные значения не достигают определенного порогового значения.
  • общий синтаксис
CREATE TABLE <TABLE_NAME>(
 tab_id SERIAL PRIMARY KEY,
 age SMALLINT CHECK(age > 21),
 parent_age SMALLINT CHECK(parent_age > age)
);
  • если ограничения нарушены, он вернет ошибку
CREATE TABLE employees (
 emp_id SERIAL PRIMARY KEY,
 first_name VARCHAR(50) NOT NULL,
 last_name VARCHAR(50) NOT NULL,
 birthdate DATE CHECK(birthdate > ‘1900–01–01’),
 hire_date DATE CHECK(hire_date > birthdate),
 salary INTEGER CHECK(salary > 0)
);
 
 
 INSERT INTO employees(
  first_name, 
  last_name, 
  birthdate, 
  hire_date, 
  salary
 )
 VALUES
 (‘toto’, ‘titi’, ‘1976–08–01’, ‘2001–10–01’, 450000);

Условные выражения и процедуры

  • добавить логику к командам и рабочим процессам в SQL

КЕЙС

  • used tp выполнять код SQL только при соблюдении определенных условий
  • аналогично ifelse в другом языке программирования
  • два основных способа использования оператора CASE:
    - общий CASE
    - выражение CASE
  • оба метода могут привести к одинаковым результатам
  • СИНТАКСИС для общего оператора CASE:
CASE
 WHEN <CONDITION_1> THEN <RESULT_1>
 WHEN <CONDITION_2> THEN <RESULT_2>
 ELSE <SOME_OTHER_RESULT>
 END
 
 
 SELECT col_1
 CASE WHEN col1 = 1 THEN ‘one’
 WHEN col1 = 2 THEN ‘two’
 ELSE ‘other’ AS <LABEL>
 END
 FROM table_1;
  • по умолчанию будет возвращать результаты в виде другого столбца с именем «case», поэтому используйте псевдоним
  • Синтаксис выражения CASE:
    - сначала оценивает выражение
    - затем последовательно сравнивает результат с каждым значением в предложениях WHEN
  • СИНТАКСИС выражения CASE:
CASE <EXPRESSION>
 WHEN <VALUE_1> THEN <RESULT_1>
 WHEN <VALUE_2> THEN <RESULT_2>
 ELSE <SOME-OTHER_RESULT>
 END
 
 
 SELECT col_1
 CASE col_1 
 WHEN 1 THEN ‘one’
 WHEN 2 THEN ‘two’
 ELSE ‘other’ AS <LABEL>
 END
 FROM table_1;

- подводить итоги:

- Общий синтаксис CASE:
- более гибкие условия (равенство, сравнение, членство в диапазоне и т. Д.)
- можно проверять различные условия в каждом предложении WHEN

Выражение CASE:
- проверено одно выражение (вызов столбца)
- только условие равенства

SELECT customer_id,
 CASE
 WHEN (customer_id <= 100)THEN ‘Premium’
 WHEN (customer_id BETWEEN 100 AND 200) THEN ‘Plus’
 ELSE ‘Normal’
 END AS customer_class
 FROM customer;
 
 
 SELECT customer_id,
 CASE customer_id
 WHEN 2 THEN ‘Winner’
 WHEN 5 THEN ‘Second Place’
 ELSE ‘Normal’
 END AS raffle_results
 FROM customer;

- вы можете использовать функции агрегирования результатов оператора CASE:

SELECT 
 SUM(
  CASE rental_rate
  WHEN 0.99 THEN 1
  ELSE 0
  END
 ) AS bargain,
 SUM(
  CASE rental_rate
  WHEN 2.99 THEN 1
  ELSE 0
  END
 ) AS regular,
 SUM(
  CASE rental_rate
  WHEN 4.99 THEN 1
  ELSE 0
  END
 ) AS premium
 FROM film;
 
# would be more difficult to do this with GROUP BY and HAVING, and would be less flexible in column display
# Compare number of movies per ratings:
SELECT
 SUM(
  CASE rating
  WHEN ‘R’ THEN 1
  ELSE 0
  END
 ) AS r,
 SUM(
  CASE rating
  WHEN ‘PG’ THEN 1
  ELSE 0
  END
 ) AS pg,
 SUM(
  CASE rating
  WHEN ‘PG-13’ THEN 1
  ELSE 0
  END
 ) AS pg13
 FROM film;

КОАЛЕС

  • Функция COALESCE принимает неограниченное количество аргументов
  • возвращает первый аргумент, который не является нулевым
  • если все аргументы равны нулю, функция COALESCE вернет ноль
  • предоставленные аргументы обычно являются именами столбцов

- СИНТАКСИС:

COALESCE( <ARG_1> , <ARG_2> , <ARG_3> , … , <ARG_N> )
SELECT COALESCE(1,2);
# returns 1
SELeCT COALESCE(NULL, 2, 3)
# returns 3
  • Функция COALESCE полезна:

- при запросе таблицы, содержащей нулевые значения
- подстановка нулевых значений другим значением

  • обычно используется при выполнении математических операций со столбцами, содержащими нулевые значения, чтобы заменить их на 0 без изменения столбцов
SELECT item, 
 (price — COALESCE(discount, 0)) AS final
 FROM table_1;
 
# when discount value is null, it will be replaced by 0

В РОЛЯХ

  • Оператор CAST, используемый для преобразования одного типа данных в другой
  • не каждый экземпляр типа данных может быть CAST для другого типа данных, это должно быть разумно
  • СИНТАКСИС для функции CAST (стандартный SQL):
SELECT CAST(‘5’ AS INTEGER)
  • Сокращенный оператор PostgreSQL CAST (::)
SELECT ‘5’::INTEGER
  • вы обычно используете его для нескольких экземпляров типа данных (столбца):
SELECT CAST(date_col AS TIMESTAMP)
 FROM table_1;
  • посчитать количество цифр в номере:
# PostgreSQL specific
 
SELECT 
 inventory_id,
 char_length(inventory_id::VARCHAR) 
FROM rental;
 
# standard SQL
SELECT 
 inventory_id,
 char_length( CAST(inventory_id AS VARCHAR) )
FROM rental

NULLIF

  • Функция NULLIF принимает 2 входа и возвращает NULL, если оба равны, в противном случае возвращает первый переданный аргумент.
NULLIF(<ARG_1>, <ARG_2>)
 
NULLIF(10, 10)
# returns NULL
NULLIF(10, 99)
# returns 10
  • очень полезно в тех случаях, когда значение NULL может вызвать ошибку или нежелательный результат
  • полезно, чтобы избежать ошибки деления на ноль (деление на ноль вернет ноль)
SELECT (
 SUM(CASE department WHEN ‘A’ THEN 1 ELSE 0 END) /
 NULLIF( 
   SUM(
     CASE department WHEN ‘B’ THEN 1 ELSE 0 END
   ),
   0
 )
) AS department_ratio
FROM depts;

ВЗГЛЯДЫ

- определенные комбинации таблиц и условий могут часто использоваться в проекте

  • вместо того, чтобы выполнять один и тот же запрос снова и снова в качестве отправной точки, создайте ВИД, чтобы быстро увидеть этот запрос с помощью простого вызова
SELECT * FROM <VIEW>
  • представление - это объект базы данных, относящийся к сохраненному запросу
  • представление может быть доступно как **** ВИРТУАЛЬНАЯ ТАБЛИЦА **** в postgresql
  • представление НЕ хранит данные физически, оно хранит ТОЛЬКО запрос
  • вы можете обновлять и изменять существующие представления
  • создать представление:
CREATE VIEW <VIEW_NAME> AS <QUERY_TO_BE_STORED>;
CREATE VIEW customer_info AS
 SELECT c.first_name, c.last_name, a.address
 FROM customer AS c
 INNER JOIN address AS a
 ON c.address_id = a.address_id;
  • запрос представления
SELECT * FROM customer_info;
  • обновить представление
CREATE OR REPLACE VIEW <VIEW_NAME> AS <QUERY_TO_BE_STORED>;
CREATE OR REPLACE VIEW customer_info AS
 SELECT c.first_name, c.last_name, a.address, a.district
 FROM customer AS c
 INNER JOIN address AS a
 ON c.address_id = a.address_id;
  • безопасно удалить представление
DROP VIEW IF EXISTS <VIEW_NAME>;
 
 DROP VIEW IF EXISTS customer_info;
  • изменить название просмотра
ALTER VIEW <VIEW_NAME> RENAME TO <NEW_VIEW_NAME>;
ALTER VIEW customer_info RENAME TO c_info;

ИМПОРТ И ЭКСПОРТ

  • с помощью pgadmin вы можете импортировать данные из файла .csv в существующую таблицу

Примечание:

ALTER TABLE <CURRENT_NAME> RENAME TO <NEW_NAME>;
  • выберите существующую таблицу в pgadmin explorer / нажмите правую кнопку мыши / «импорт / экспорт»
    / нажмите кнопку переключения экспорта, чтобы отобразить импорт
    / выбрать файл на вашем хосте
    / в таблице столбцов, вы можете выбрать столбцы для импорта
    / если файл csv имеет заголовки, нажмите кнопку заголовков, чтобы не дублировать их как значения
    / выберите разделитель
    / отправьте форму
  • для экспорта, аналогичный процесс, выберите таблицу / щелкните правой кнопкой мыши / «импорт / экспорт»
    укажите файл для экспорта
    установите желаемый разделитель и другие параметры

Вот и все

Теперь вы знаете достаточно, чтобы быть опасным с SQL, и понимаете запросы, выполняемые ORM за кулисами. Есть еще много чего узнать, так что продолжайте!

Чтобы увидеть больше моих историй: