Блюдо | Вид | Дата | Продукт | Калорийность | Вес (г) | Поставщик | Город | Страна | Цена ($) |
---|---|---|---|---|---|---|---|---|---|
Лобио | Закуска | 01.09.2012 | Фасоль | 307 | 200 | "Хуанхэ" | Пекин | Китай | 0.37 |
Лобио | Закуска | 01.09.2012 | Лук | 45 | 40 | "Наталка" | Киев | Украина | 0.52 |
Лобио | Закуска | 01.09.2012 | Масло | 742 | 30 | "Лайма" | Рига | Латвия | 1.55 |
Лобио | Закуска | 01.09.2012 | Зелень | 18 | 10 | "Даугава" | Рига | Латвия | 0.99 |
Борщ | Суп | 01.09.2012 | Мясо | 166 | 80 | "Наталка" | Киев | Украина | 2.18 |
Борщ | Суп | 01.09.2012 | Лук | 45 | 30 | "Наталка" | Киев | Украина | 0.52 |
Борщ | Суп | 01.09.2012 | Томаты | 24 | 40 | "Полесье" | Киев | Украина | 0.45 |
Борщ | Суп | 01.09.2012 | Рис | 334 | 50 | "Хуанхэ" | Пекин | Китай | 0.44 |
Борщ | Суп | 01.09.2012 | Масло | 742 | 15 | "Полесье" | Киев | Украина | 1.62 |
Борщ | Суп | 01.09.2012 | Зелень | 18 | 15 | "Наталка" | Киев | Украина | 0.88 |
Заголовок | Дата | Автор | Текст | Оценка | Ответы | |
---|---|---|---|---|---|---|
Руслан и Людмила | 01.01.1820 | Пушкин А.С. | sukin_syn@mail.ru | … | 500 | 120 |
Война и Мир | 01.03.1869 | Толстой Л.Н. | tolstoy@inbox.ru | … | 100 | 345 |
Отцы и Дети | 15.08.1862 | Иван Тургенев | nedobobov@mail.ru | … | 256 | 18 |
Повести Белкина | 12.06.1830 | Пушкин А.С. | sukin_syn@mail.ru | … | 400 | 96 |
Муму | 10.11.1852 | Иван Тургенев | nedobobov@mail.ru | … | 312 | 46 |
Первичный ключ выбирается исходя из соображений удобства и сохранения уникальности. Если такого ключа нет, то имеет смысл добавить специальное поле.
TopicID | Заголовок | Дата | Автор | Текст | Оценка | Ответы | |
---|---|---|---|---|---|---|---|
5 | Руслан и Людмила | 01.01.1820 | Пушкин А.С. | sukin_syn@mail.ru | … | 500 | 120 |
8 | Война и Мир | 01.03.1869 | Толстой Л.Н. | tolstoy@inbox.ru | … | 100 | 345 |
12 | Отцы и Дети | 15.08.1862 | Иван Тургенев | nedobobov@mail.ru | … | 256 | 18 |
43 | Повести Белкина | 12.06.1830 | Пушкин А.С. | sukin_syn@mail.ru | … | 400 | 96 |
16 | Муму | 10.11.1852 | Иван Тургенев | nedobobov@mail.ru | … | 312 | 46 |
Пароль | Имя | Дата | Привилегии | Разделы | |
---|---|---|---|---|---|
tolstoy@mail.ru | ***** | Толстой Л.Н. | 09.09.1828 | Админ, Модератор | Новости, Флуд |
saltykov@inbox.ru | ***** | Николай Щедрин | 27.01.1826 | Модератор | Флуд, Юмор |
fmd@mail.ru | ***** | Федор Михайлович | 11.11.1821 | Игрок | |
sukin_syn@mail.ru | ***** | Пушкин А.С. | 06.06.1799 | Админ | Поэзия |
Переменная отношения находится в первой нормальной форме (1НФ) тогда и только тогда, когда в любом допустимом значении отношения каждый его кортеж содержит только одно значение для каждого из атрибутов.
Пароль | Имя | Дата | Привилегии | Разделы | |
---|---|---|---|---|---|
tolstoy@mail.ru | ***** | Толстой Л.Н. | 09.09.1828 | Админ, Модератор | Новости, Флуд |
saltykov@inbox.ru | ***** | Николай Щедрин | 27.01.1826 | Модератор | Флуд, Юмор |
fmd@mail.ru | ***** | Федор Михайлович | 11.11.1821 | Игрок | |
sukin_syn@mail.ru | ***** | Пушкин А.С. | 06.06.1799 | Админ | Поэзия |
Переменная отношения находится в первой нормальной форме (1НФ) тогда и только тогда, когда в любом допустимом значении отношения каждый его кортеж содержит только одно значение для каждого из атрибутов.
Пароль | Имя | Дата | Привилегии | Разделы | |
---|---|---|---|---|---|
tolstoy@mail.ru | ***** | Толстой Л.Н. | 09.09.1828 | Админ | Новости |
tolstoy@mail.ru | ***** | Толстой Л.Н. | 09.09.1828 | Админ | Флуд |
tolstoy@mail.ru | ***** | Толстой Л.Н. | 09.09.1828 | Модератор | Новости |
tolstoy@mail.ru | ***** | Толстой Л.Н. | 09.09.1828 | Модератор | Флуд |
saltykov@inbox.ru | ***** | Николай Щедрин | 27.01.1826 | Модератор | Флуд |
saltykov@inbox.ru | ***** | Николай Щедрин | 27.01.1826 | Модератор | Юмор |
fmd@mail.ru | ***** | Федор Михайлович | 11.11.1821 | Игрок | |
sukin_syn@mail.ru | ***** | Пушкин А.С. | 06.06.1799 | Админ | Поэзия |
Переменная отношения находится во второй нормальной форме тогда и только тогда, когда она находится в первой нормальной форме, и каждый неключевой атрибут неприводимо зависит от ее потенциального ключа.
Пароль | Имя | Дата | Привилегии | Разделы | |
---|---|---|---|---|---|
tolstoy@mail.ru | ***** | Толстой Л.Н. | 09.09.1828 | Админ | Новости |
tolstoy@mail.ru | ***** | Толстой Л.Н. | 09.09.1828 | Админ | Флуд |
tolstoy@mail.ru | ***** | Толстой Л.Н. | 09.09.1828 | Модератор | Новости |
tolstoy@mail.ru | ***** | Толстой Л.Н. | 09.09.1828 | Модератор | Флуд |
saltykov@inbox.ru | ***** | Николай Щедрин | 27.01.1826 | Модератор | Флуд |
saltykov@inbox.ru | ***** | Николай Щедрин | 27.01.1826 | Модератор | Юмор |
fmd@mail.ru | ***** | Федор Михайлович | 11.11.1821 | Игрок | |
sukin_syn@mail.ru | ***** | Пушкин А.С. | 06.06.1799 | Админ | Поэзия |
Переменная отношения находится во второй нормальной форме тогда и только тогда, когда она находится в первой нормальной форме, и каждый неключевой атрибут неприводимо зависит от ее потенциального ключа.
Пароль | Имя | Дата | |
---|---|---|---|
tolstoy@mail.ru | ***** | Толстой Л.Н. | 09.09.1828 |
saltykov@inbox.ru | ***** | Николай Щедрин | 27.01.1826 |
fmd@mail.ru | ***** | Федор Михайлович | 11.11.1821 |
sukin_syn@mail.ru | ***** | Пушкин А.С. | 06.06.1799 |
Привилегии | Разделы | |
---|---|---|
tolstoy@mail.ru | Админ | Новости |
tolstoy@mail.ru | Админ | Флуд |
tolstoy@mail.ru | Модератор | Новости |
tolstoy@mail.ru | Модератор | Флуд |
saltykov@inbox.ru | Модератор | Флуд |
saltykov@inbox.ru | Модератор | Юмор |
fmd@mail.ru | Игрок | |
sukin_syn@mail.ru | Админ | Поэзия |
Переменная отношения находится в третьей нормальной форме, когда она находится во второй нормальной форме, и отсутствуют транзитивные функциональные зависимости неключевых атрибутов от ключевых.
TopicID | Заголовок | Дата | Автор | Текст | Оценка | Ответы | |
---|---|---|---|---|---|---|---|
5 | Руслан и Людмила | 01.01.1820 | Пушкин А.С. | sukin_syn@mail.ru | … | 500 | 120 |
8 | Война и Мир | 01.03.1869 | Толстой Л.Н. | tolstoy@inbox.ru | … | 100 | 345 |
12 | Отцы и Дети | 15.08.1862 | Иван Тургенев | nedobobov@mail.ru | … | 256 | 18 |
43 | Повести Белкина | 12.06.1830 | Пушкин А.С. | sukin_syn@mail.ru | … | 400 | 96 |
16 | Муму | 10.11.1852 | Иван Тургенев | nedobobov@mail.ru | … | 312 | 46 |
Переменная отношения находится в третьей нормальной форме, когда она находится во второй нормальной форме, и отсутствуют транзитивные функциональные зависимости неключевых атрибутов от ключевых.
Автор | |
---|---|
sukin_syn@mail.ru | Пушкин А.С. |
tolstoy@inbox.ru | Толстой Л.Н. |
nedobobov@mail.ru | Иван Тургенев |
TopicID | Заголовок | Дата | Текст | Оценка | Ответы | |
---|---|---|---|---|---|---|
5 | Руслан и Людмила | 01.01.1820 | sukin_syn@mail.ru | … | 500 | 120 |
8 | Война и Мир | 01.03.1869 | tolstoy@inbox.ru | … | 100 | 345 |
12 | Отцы и Дети | 15.08.1862 | nedobobov@mail.ru | … | 256 | 18 |
43 | Повести Белкина | 12.06.1830 | sukin_syn@mail.ru | … | 400 | 96 |
16 | Муму | 10.11.1852 | nedobobov@mail.ru | … | 312 | 46 |
Переменная отношения находится в четвёртой нормальной форме, если она находится в третьей нормальной форме и не содержит нетривиальных многозначных зависимостей.
Привилегии | Разделы | |
---|---|---|
tolstoy@mail.ru | Админ | Новости |
tolstoy@mail.ru | Админ | Флуд |
tolstoy@mail.ru | Модератор | Новости |
tolstoy@mail.ru | Модератор | Флуд |
saltykov@inbox.ru | Модератор | Флуд |
saltykov@inbox.ru | Модератор | Юмор |
fmd@mail.ru | Игрок | |
sukin_syn@mail.ru | Админ | Поэзия |
Переменная отношения находится в четвёртой нормальной форме, если она находится в третьей нормальной форме и не содержит нетривиальных многозначных зависимостей.
Привилегии | |
---|---|
tolstoy@mail.ru | Админ |
tolstoy@mail.ru | Модератор |
saltykov@inbox.ru | Модератор |
fmd@mail.ru | Игрок |
sukin_syn@mail.ru | Админ |
Разделы | |
---|---|
tolstoy@mail.ru | Новости |
tolstoy@mail.ru | Флуд |
saltykov@inbox.ru | Флуд |
saltykov@inbox.ru | Юмор |
fmd@mail.ru | |
sukin_syn@mail.ru | Поэзия |
CREATE [ { TEMPORARY } | UNLOGGED ] TABLE [ IF NOT EXISTS ] table_name ( [
{ column_name data_type [ COLLATE collation ] [ column_constraint [ ... ] ]
| table_constraint
| LIKE source_table [ like_option ... ] }
[, ... ]
] )
[ INHERITS ( parent_table [, ... ] ) ]
[ WITH ( storage_parameter [= value] [, ... ] ) | WITH OIDS | WITHOUT OIDS ]
[ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
[ TABLESPACE tablespace_name ]
Or:
CREATE [ { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXISTS ] table_name
OF type_name [ (
{ column_name WITH OPTIONS [ column_constraint [ ... ] ]
| table_constraint }
[, ... ]
) ]
[ WITH ( storage_parameter [= value] [, ... ] ) | WITH OIDS | WITHOUT OIDS ]
[ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
[ TABLESPACE tablespace_name ]
[ CONSTRAINT constraint_name ]
{ NOT NULL |
NULL |
DEFAULT default_expr |
CHECK ( expression ) [ NO INHERIT ] |
UNIQUE index_parameters |
PRIMARY KEY index_parameters |
REFERENCES reftable [ ( refcolumn ) ]
[ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ]
[ ON DELETE action ] [ ON UPDATE action ] }
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
[ CONSTRAINT constraint_name ]
{ CHECK ( expression ) [ NO INHERIT ] |
UNIQUE ( column_name [, ... ] ) index_parameters |
PRIMARY KEY ( column_name [, ... ] ) index_parameters |
FOREIGN KEY ( column_name [, ... ] )
REFERENCES reftable [ ( refcolumn [, ... ] ) ]
[ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ]
[ ON DELETE action ] [ ON UPDATE action ] }
EXCLUDE [ USING index_method ] ( exclude_element WITH operator [, ... ] )
index_parameters [ WHERE ( predicate ) ] |
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
CREATE TABLE films (
code char(5) CONSTRAINT firstkey PRIMARY KEY,
title varchar(40) NOT NULL,
date_prod date,
kind varchar(10),
len interval hour to minute,
imdb varchar(20) NULL,
CONSTRAINT uniq_imdb UNIQUE(imdb)
);
CREATE TABLE distributors (
did integer PRIMARY KEY DEFAULT nextval('serial'),
name varchar(40) NOT NULL CHECK (name <> '')
);
ALTER TABLE [ IF EXISTS ] [ ONLY ] name [ * ]
action [, ... ]
ALTER TABLE [ IF EXISTS ] [ ONLY ] name [ * ]
RENAME [ COLUMN ] column_name TO new_column_name
ALTER TABLE [ IF EXISTS ] [ ONLY ] name [ * ]
RENAME CONSTRAINT constraint_name TO new_constraint_name
ALTER TABLE [ IF EXISTS ] name
RENAME TO new_name
ADD [ COLUMN ] [ IF NOT EXISTS ] column_name data_type [ ... ]
DROP [ COLUMN ] [ IF EXISTS ] column_name [ RESTRICT | CASCADE ]
ALTER [ COLUMN ] column_name [ SET DATA ] TYPE data_type [ USING expression ]
ALTER [ COLUMN ] column_name SET DEFAULT expression
ALTER [ COLUMN ] column_name DROP DEFAULT
ADD table_constraint [ NOT VALID ]
DROP CONSTRAINT [ IF EXISTS ] constraint_name [ RESTRICT | CASCADE ]
...
ALTER TABLE distributors
ADD COLUMN address varchar(30),
DROP COLUMN address RESTRICT,
ALTER COLUMN address TYPE varchar(80),
ALTER COLUMN name TYPE varchar(100);
ALTER TABLE foo
ALTER COLUMN foo_timestamp DROP DEFAULT,
ALTER COLUMN foo_timestamp TYPE timestamp with time zone
USING
timestamp with time zone 'epoch'
+ foo_timestamp * interval '1 second',
ALTER COLUMN foo_timestamp SET DEFAULT now();
[ WITH [ RECURSIVE ] with_query [, ...] ]
SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]
[ * | expression [ [ AS ] output_name ] [, ...] ]
[ FROM from_item [, ...] ]
[ WHERE condition ]
[ GROUP BY grouping_element [, ...] ]
[ HAVING condition [, ...] ]
[ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ] select ]
[ ORDER BY expression [ ASC | DESC | USING operator ] [, ...] ]
[ LIMIT { count | ALL } ]
[ OFFSET start [ ROW | ROWS ] ]
[ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY ]
[ FOR { UPDATE | NO KEY UPDATE | SHARE | KEY SHARE }
[ OF table_name [, ...] ] [ NOWAIT | SKIP LOCKED ] [...] ]
SELECT *
FROM persons
WHERE department_id IN (
SELECT id FROM departments WHERE company_id = 42
)
CASE WHEN condition THEN result
[WHEN ...]
[ELSE result]
END
NULLIF(value1, value2)
GREATEST(value [, ...])
LEAST(value [, ...])
SELECT a,
CASE WHEN a=1 THEN 'one'
WHEN a=2 THEN 'two'
ELSE 'other'
END
FROM test;
SELECT * FROM employee;
id | name | department | grade |
---|---|---|---|
1 | John | HR | A |
2 | Mark | HR | A |
3 | Smit | IT | A |
4 | Lili | IT | B |
5 | Alex | PR | B |
6 | Walton | HR | B |
7 | Kim | PR | B |
8 | Marry | HR | A |
9 | Paul | PR | C |
10 | Christ | HR | A |
11 | Jiji | HR | B |
12 | Bob | PR | B |
SELECT grade, department, COUNT(*)
FROM employee
GROUP BY grade, department
ORDER BY grade, department;
grade | department | COUNT(*) |
---|---|---|
A | HR | 4 |
A | IT | 1 |
B | HR | 2 |
B | IT | 1 |
B | PR | 3 |
C | PR | 1 |
aggregate_name (
[ ALL | DISTINCT ] expression [ , ... ]
[ order_by_clause ]
) [ FILTER ( WHERE filter_clause ) ]
SELECT
string_agg(name, ',' ORDER BY name),
avg(age),
count(*) FILTER (WHERE age BETWEEN 13 AND 19) AS teens
FROM persons;
Функция | Описание |
---|---|
avg(expression) | Среднее арифмитическое |
max(expression) | Максимальное значение |
min(expression) | Минимальное значение |
sum(expression) | Сумма |
count(*) | Кол-во строк |
count(expression) | Кол-во не NULL-значений |
Функция | Описание |
---|---|
bit_and(expression) | Битовое "И" |
bit_or(expression) | Битовое "ИЛИ" |
bool_and(expression), every(expression) | Логическое "И" |
bool_or(expression) | Логическое "ИЛИ" |
stddev(expression) | Стандартное отклонение |
variance(expression) | Дисперсия (квадрат отклонения) |
Функция | Описание |
---|---|
array_agg(expression) | Сформировать массив значений |
json_agg(expression) | Сформировать JSON-массив |
jsonb_agg(expression) | Сформировать JSONB-массив |
json_object_agg(key, value) | Сформировать JSON-объект |
jsonb_object_agg(key, value) | Сформировать JSONB-объект |
string_agg(expression, delimiter) | Конкатенация строк |
xmlagg(expression) | Конкатенация XML-элементов |
SELECT grade, department, COUNT(*)
FROM employee
GROUP BY grade, department
HAVING COUNT(*) > 3;
SELECT * FROM (
SELECT grade, department, COUNT(*) as employee_cnt
FROM employee
GROUP BY grade, department
) a
WHERE employee_cnt > 3;
SELECT select_list
FROM table_expression
ORDER BY sort_expression1 [ASC | DESC] [NULLS { FIRST | LAST }]
[, sort_expression2 [ASC | DESC] [NULLS { FIRST | LAST }] ...]
SELECT a, b FROM table1 ORDER BY a + b, c;
SELECT a + b AS sum, c FROM table1 ORDER BY sum;
SELECT a, max(b) FROM table1 GROUP BY a ORDER BY 1;
# SELECT a + b AS sum, c FROM table1 ORDER BY sum + c;
ERROR: column "sum" does not exist
LINE 1: SELECT a + b AS sum, c FROM table1 ORDER BY sum + c;
^
SELECT * FROM (
SELECT
ROW_NUMBER() OVER (ORDER BY age ASC) AS rownumber,
person_id, person_name, age
FROM person
) AS foo
WHERE rownumber <= 10;
SELECT * FROM (
SELECT
RANK() OVER (ORDER BY age ASC) AS ranking,
person_id, person_name, age
FROM person
) AS foo
WHERE ranking <= 10;
SELECT
person_id, person_name, age
FROM person
LIMIT 10
OFFSET 20;
SELECT
person_id, person_name, age
FROM person
FETCH FIRST 10 ROWS ONLY;
WITH regional_sales AS (
SELECT region, SUM(amount) AS total_sales
FROM orders
GROUP BY region
),
top_regions AS (
SELECT region
FROM regional_sales
WHERE total_sales > (SELECT SUM(total_sales)/10 FROM regional_sales)
)
SELECT region,
product,
SUM(quantity) AS product_units,
SUM(amount) AS product_sales
FROM orders
WHERE region IN (SELECT region FROM top_regions)
GROUP BY region, product;
WITH RECURSIVE recursetree (id, parent_id, level, name) AS (
SELECT id, parent_id, 0, name FROM tree
WHERE parent_id = 0
UNION ALL
SELECT t.id, t.parent_id, level+1, t.name
FROM tree t
JOIN recursetree rt ON rt.id = t.parent_id
)
SELECT * FROM recursetree;
id | parent | level | name |
---|---|---|---|
1 | 0 | 0 | Россия |
2 | 0 | 0 | США |
3 | 1 | 1 | Москва |
4 | 2 | 1 | Нью Йорк |
5 | 2 | 1 | Вашингтон |
6 | 3 | 2 | Бутово |
WITH RECURSIVE recursetree (id, path, name) AS (
SELECT id, array_append('{}'::int[], id), name FROM tree
WHERE parent_id = 0
UNION ALL
SELECT t.id, array_append(path, t.id), t.name
FROM tree t
JOIN recursetree rt ON rt.id = t.parent_id
)
SELECT id, array_to_string(path, '.') as path, name FROM recursetree
ORDER BY path;
id | path | name |
---|---|---|
1 | 1 | Россия |
3 | 1.3 | Москва |
6 | 1.3.6 | Бутово |
2 | 2 | США |
4 | 2.4 | Нью Йорк |
5 | 2.5 | Вашингтон |
[ WITH [ RECURSIVE ] with_query [, ...] ]
INSERT INTO table_name [ AS alias ] [ ( column_name [, ...] ) ]
{ DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] ) [, ...] | query }
[ ON CONFLICT [ conflict_target ] conflict_action ]
[ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]
( { index_column_name | ( index_expression ) } ... [, ...] )
[ WHERE index_predicate ]
ON CONSTRAINT constraint_name
DO NOTHING
DO UPDATE SET { column_name = { expression | DEFAULT } |
( column_name [, ...] ) = ( { expression | DEFAULT } [, ...] ) |
( column_name [, ...] ) = ( sub-SELECT )
} [, ...]
[ WHERE condition ]
INSERT INTO films (code, title, did, date_prod, kind) VALUES
('B6717', 'Tampopo', 110, '1985-02-10', 'Comedy'),
('HG120', 'The Dinner Game', 140, DEFAULT, 'Comedy')
RETURNING *;
INSERT INTO films
SELECT * FROM tmp_films WHERE date_prod < '2004-05-07';
INSERT INTO distributors (id, dname)
VALUES (5, 'Gizmo Transglobal'), (6, 'Associated Computing, Inc')
ON CONFLICT (id) DO UPDATE SET dname = EXCLUDED.dname;
INSERT INTO distributors (id, dname) VALUES (7, 'Redline GmbH')
ON CONFLICT (id) DO NOTHING;
[ WITH [ RECURSIVE ] with_query [, ...] ]
UPDATE [ ONLY ] table_name [ * ] [ [ AS ] alias ]
SET { column_name = { expression | DEFAULT } |
( column_name [, ...] ) = ( { expression | DEFAULT } [, ...] ) |
( column_name [, ...] ) = ( sub-SELECT )
} [, ...]
[ FROM from_list ]
[ WHERE condition | WHERE CURRENT OF cursor_name ]
[ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]
UPDATE table1
SET
col_name1 = col_name2,
col_name2 = col_name1
WHERE id = 42;
UPDATE weather
SET temp_lo = temp_lo+1, temp_hi = temp_lo+15, prcp = DEFAULT
WHERE city = 'San Francisco' AND date = '2003-07-03'
RETURNING temp_lo, temp_hi, prcp;
UPDATE weather
SET (temp_lo, temp_hi, prcp) = (temp_lo+1, temp_lo+15, DEFAULT)
WHERE city = 'San Francisco' AND date = '2003-07-03'
RETURNING temp_lo, temp_hi, prcp;
UPDATE accounts SET
contact_first_name = (
SELECT first_name FROM salesmen WHERE salesmen.id = accounts.sales_id
),
contact_last_name = (
SELECT last_name FROM salesmen WHERE salesmen.id = accounts.sales_id
);
UPDATE accounts SET (contact_first_name, contact_last_name) =
(SELECT first_name, last_name FROM salesmen
WHERE salesmen.id = accounts.sales_id);
UPDATE accounts SET contact_first_name = first_name,
contact_last_name = last_name
FROM salesmen WHERE salesmen.id = accounts.sales_id;
[ WITH [ RECURSIVE ] with_query [, ...] ]
DELETE FROM [ ONLY ] table_name [ * ] [ [ AS ] alias ]
[ USING using_list ]
[ WHERE condition | WHERE CURRENT OF cursor_name ]
[ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]
DELETE FROM films;
TRUNCATE [ TABLE ] [ ONLY ] name [ * ] [, ... ]
[ RESTART IDENTITY | CONTINUE IDENTITY ] [ CASCADE | RESTRICT ]
TRUNCATE TABLE films;
DELETE FROM films WHERE kind <> 'Musical';
DELETE FROM tasks WHERE status = 'DONE' RETURNING *;
DELETE FROM films
WHERE producer_id IN (SELECT id FROM producers WHERE name = 'foo');
DELETE FROM films USING producers
WHERE producer_id = producers.id AND producers.name = 'foo';
Главный недостаток такого подхода — необходимо достоверно знать количество уровней вложенности в вашей иерархии, кроме того, чем больше иерархия, тем больше JOIN'ов — тем ниже производительность.
Тем не менее, данный способ обладает и существенными достоинствами — в дерево легко вносить изменения, менять местами и удалять узлы.
Данный алгоритм хорошо применим, если вы оперируете с небольшими древовидными структурами, которые часто поддаются изменениям.
С другой стороны, этот алгоритм также довольно уверенно себя чувствует и с большими деревьями, если считывать их порциями вида «знаю родителя — прочитать всех наследников». Хороший пример такого случая — динамически подгружаемые деревья.
Однако он плохо применим, когда нужно вычитывать какие-либо иные куски дерева, находить пути, предыдущие и следующие узлы при обходе и вычитывать ветки дерева целиком (на всю глубину).
Nested Set действительно хорош, когда нам необходимо считывать структуру деревьев из БД. При этом он одинаково хорош для деревьев любого объема.
Тем не менее, для иерархических структур, которые подвергаются частому изменению он, очевидно, не будет являться оптимальным выбором.
Во-первых, по сравнению с Nested Set, он более поддается изменениям. В то же время остается достаточно удобным для выборки деревьев целиком и их частей. Но, и он не идеален. Особенно по части поиска предков ветки.
Использование именно этого алгоритма может быть заметно удобнее, для деревьев, над которыми часто выполняются как операции чтения, так и изменения.
Алгоритм довольно уверенно себя чувствует на достаточно больших объемах данных.
Наиболее неприятной в данном алгоритме будет операция вставки узла в середину уже существующей структуры и перенос одной ветки в другую.
А вот удаление, добавление в конец или изменение узла — это операции довольно простые, и, как правило, не вызывают сложностей в данной модели.
По сути вопроса следует отметить, что скомбинировать приведенные методы можно лишь в двух направлениях:
Комбинировать же Nested Set и Materialized Path особого смысла не имеет, т.к. существенного выигрыша ни в чтении, ни в записи вы не получите.
Для связки AL+NS взаимовыгодность не столь очевидна.
В первую очередь это объясняется тем, что недостатки от проблем изменения узлов дерева в модели NS напрочь убивают в этой сфере все достоинства AL.
Это значит, что такую связку следует рассматривать лишь как качественное улучшение поиска родителей и наследников заданного узла в алгоритме NS, а также как повышение надежности самого алгоритма (ключи можно всегда перестроить в случае порчи — информацию о связях хранит AL).
Но ведь и это качественное улучшение, хотя и не такое очевидное.