Документация по PostgreSQL 8.2devel | ||||
---|---|---|---|---|
Prev | Fast Backward | Chapter 7. Запросы | Fast Forward | Next |
Табличное выражение в итоге даёт некую таблицу. Табличное выражение содержит преложение FROM, за которым могут следовать необязательные предложения WHERE, GROUP BY и HAVING. Простейшее табличное выражение просто указывает на какую-либо таблицу, расположенную на диске, которую также называют базовой таблицей, но для различных способов комбинирования нескольких базовых таблиц могут использоваться более сложные выражения.
Необязательные предожения WHERE, GROUP BY и HAVING в табличном выражении, задают порядок последовательных преобразований, выполняемых над таблицей, полученной в предложении FROM. Все эти преобразования в итоге выдают некую виртуальную таблицу, строки которой передаются в список выборки, чтобы затем вычислить итоговые строки, которые будут выданы запросом.
Предложение FROM Clause производит таблицу из одной или более других таблиц, которые задаются в списке таблиц, разделяемые запятой.
FROM ссылка_на_таблицу [, ссылка_на_таблицу [, ...]]
Ссылка на таблицу может быть именем таблицы (возможно с указанием имени схемы) или производной таблицей, такой как подзапрос, объединение таблиц или сложной комбинацией из всех этих элементов. Если в списке предложения FROM задано более одной ссылки на таблицу, то они все объединяются между собой (см. ниже) для формирования сборной виртуальной таблицы, которая может затем быть подвергнута преобразованиям с помощью предложений WHERE, GROUP BY и HAVING и в заключение выдана как результат всего табличного выражения.
Когда ссылка на таблицу — это имя таблицы, которая является супертаблицей в табличной иерархии наследования, то это ссылка выдаёт строки не только таблицы с указанным именем, но и всех других подтаблиц, которые расположены ниже в иерархии наследования, если только перед именем таблицы не будет стоять ключевое слово ONLY. Однако, данная ссылка на таблицу выдаёт только те колонки, которые есть в таблице с указанным именем — все остальные колонки, которые были добавлены в подтаблицы игнорируются.
Объединённая таблица — это таблица, полученная из двух других (реальных или производных) таблиц, в соответствии с правилами определённого типа объединения. Доступны такие типы объдинения как внутренее объединение, внешнее объединение и пересечение.
Типы объдинения
T1 CROSS JOIN T2
Для каждой комбинации строк из таблицы T1 и таблицы T2, итоговая таблица будет содержать строку, которая содержит все колонки таблицы T1, за которыми следуют все колонки в таблице T2. Если эти таблицы имеют соответственно N и M строк, то объединённая таблица будет иметь N * M строк.
Преложение FROM T1 CROSS JOIN T2 эквивалентно FROM T1, T2. Оно также эквивалетно предложению FROM T1 INNER JOIN T2 ON TRUE (см. ниже).
T1 { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2 ON логическое_выражение T1 { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2 USING ( список объединяемых колонок ) T1 NATURAL { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2
Слова INNER и OUTER являются необязательными в любой из форм синтаксиса. По умолчанию используется INNER; слова LEFT, RIGHT, and FULL неявно означают внешнее объединение.
Условие объединения задаётся в предложении ON или USING, или неявно с помощью слова NATURAL. Условие объединения определяет какие строки из двух исходных таблиц считаются "совпавшими", как объясняется в подробностях ниже.
Предложение ON является наиболее общим видом условия объединения: оно использует логическое выражение того же вида, что используется в предложении WHERE. Пара строк из таблиц T1 и T2 совпадают, если выражение ON для них возвращает значение "истина".
Предложение USING в краткой нотации: оно использует список, разделённых запятыми, имён колонок, которые должны быть общими для соединяемых таблиц, и формы условия объединения задаются одинаково для каждой из этих пар колонок. Следовательно, вывод JOIN USING имеет одну колонку для каждой одинаковой пары входных колонок, за которой следуют все другие колонки из каждой таблицы. Таким образом, USING (a, b, c) эквивалентно ON (t1.a = t2.a AND t1.b = t2.b AND t1.c = t2.c) за исключением того, что если ON используется там где будет две колонки a, b и c как результат, то USING там где будет только одна из каждой.
Наконец, NATURAL — это краткая форма USING: она формирует список USING, содержащий точно те имена колонок, которые есть в обоих входных таблицах. Как и с USING, эти колонки в выходной таблице будут встречаться только один раз.
Возможны следующие типы полного соединения:
Для каждой строки R1 в таблице T1, объединённая таблица будет иметь строку для каждой строки в таблице T2, если эта строка отвечает условию объединения с R1.
Сперва выполняется INNER JOIN. Затем, для каждой строки в таблице T1, которая не соответствует условию объединения с любой строкой в T2, добавляется объединённая строка с значением null в колонках таблицы T2. Таким образом, объединённая таблица безусловно имеет по крайней мере одну строку для каждой строки таблицы T1.
Сперва выполняется INNER JOIN. Затем, для каджой строки в таблице T2, которая не соответствует условию объединения с любой строкой в таблице T1, добавляется объединённая строка с значением null в колонках таблицы T1. Таким образом, такое объединение является обратным по отношению к LEFT JOIN: результирующая таблица будет безусловно иметь строку для каждой строки в T2.
Сперва выполняется INNER JOIN. Затем, для каждой строки в таблице T1, которая не соответствует условию объединения с любой строкой в T2, добавляется объединённая строка с значениями null в колонках таблицы T2. Также, для каждой строки в таблице T2, которая не соответствует условию объединения с любой строкой в T1, добавляется объединённая строка с значениями null в колонках таблицы T1.
Объединения всех типов могут выполняться вложено или раздельно: при объединении таблицы T1 и T2 могут использоваться как по одиночке так и вместе. Чтобы управлять порядком выполнения объединений, вокруг предложений JOIN могут быть использованы круглые скобки. В отсутствии скобок, предложения JOIN выполняются раздельно слева направо.
Чтобы выполнить объединения таблиц, предположим, что у нас есть таблицы t1
num | name -----+------ 1 | a 2 | b 3 | c
и t2
num | value -----+------- 1 | xxx 3 | yyy 5 | zzz
и вот какие результаты мы получим при разные типах объединения:
=> SELECT * FROM t1 CROSS JOIN t2; num | name | num | value -----+------+-----+------- 1 | a | 1 | xxx 1 | a | 3 | yyy 1 | a | 5 | zzz 2 | b | 1 | xxx 2 | b | 3 | yyy 2 | b | 5 | zzz 3 | c | 1 | xxx 3 | c | 3 | yyy 3 | c | 5 | zzz (9 строк) => SELECT * FROM t1 INNER JOIN t2 ON t1.num = t2.num; num | name | num | value -----+------+-----+------- 1 | a | 1 | xxx 3 | c | 3 | yyy (2 строки) => SELECT * FROM t1 INNER JOIN t2 USING (num); num | name | value -----+------+------- 1 | a | xxx 3 | c | yyy (2 строки) => SELECT * FROM t1 NATURAL INNER JOIN t2; num | name | value -----+------+------- 1 | a | xxx 3 | c | yyy (2 строки) => SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num; num | name | num | value -----+------+-----+------- 1 | a | 1 | xxx 2 | b | | 3 | c | 3 | yyy (3 rows) => SELECT * FROM t1 LEFT JOIN t2 USING (num); num | name | value -----+------+------- 1 | a | xxx 2 | b | 3 | c | yyy (3 строки) => SELECT * FROM t1 RIGHT JOIN t2 ON t1.num = t2.num; num | name | num | value -----+------+-----+------- 1 | a | 1 | xxx 3 | c | 3 | yyy | | 5 | zzz (3 строки) => SELECT * FROM t1 FULL JOIN t2 ON t1.num = t2.num; num | name | num | value -----+------+-----+------- 1 | a | 1 | xxx 2 | b | | 3 | c | 3 | yyy | | 5 | zzz (4 строки)
Условие объединения, которое задаётся с ON может также содержать условия, которые непосредственно не относятся к объединению. Это может оказаться полезным для некоторых запросов, но необходимо соблюдать осторожность. Например:
=> SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num AND t2.value = 'xxx'; num | name | num | value -----+------+-----+------- 1 | a | 1 | xxx 2 | b | | 3 | c | | (3 строки)
Для обычных и сложных таблиц могут быть назначены псевдонимы, которые затем могут быть использованы для ссылок на производные таблицы в остальной части запроса. Они называются псевдним таблицы.
Чтобы создать псевдоним таблицы, напишите
FROM ссылка_на_таблицу AS псевдоним
или
FROM ссылка_на_таблицу псевдоним
Ключевое слово AS не является обязательным. Псевдоним может быть любым идентификатором.
Обычное применение псевдонимов таблиц состоит в назначении более короткого идентифкатора для длинного имени таблицы, чтобы сделать, например, запрос объединения таблиц более читабельным. Например:
SELECT * FROM some_very_long_table_name s JOIN another_fairly_long_name a ON s.id = a.num;
The alias becomes the new name of the table reference for the current query — it is no longer possible to refer to the table by the original name. Thus
SELECT * FROM my_table AS m WHERE my_table.a > 5;
is not valid SQL syntax. What will actually happen (this is a PostgreSQL extension to the standard) is that an implicit table reference is added to the FROM clause, so the query is processed as if it were written as
SELECT * FROM my_table AS m, my_table AS my_table WHERE my_table.a > 5;
which will result in a cross join, which is usually not what you want.
Table aliases are mainly for notational convenience, but it is necessary to use them when joining a table to itself, e.g.,
SELECT * FROM my_table AS a CROSS JOIN my_table AS b ...
Additionally, an alias is required if the table reference is a subquery (see Section 7.2.1.3).
Parentheses are used to resolve ambiguities. The following statement will assign the alias b to the result of the join, unlike the previous example:
SELECT * FROM (my_table AS a CROSS JOIN my_table) AS b ...
Another form of table aliasing gives temporary names to the columns of the table, as well as the table itself:
FROM table_reference [AS] alias ( column1 [, column2 [, ...]] )
If fewer column aliases are specified than the actual table has columns, the remaining columns are not renamed. This syntax is especially useful for self-joins or subqueries.
When an alias is applied to the output of a JOIN clause, using any of these forms, the alias hides the original names within the JOIN. For example,
SELECT a.* FROM my_table AS a JOIN your_table AS b ON ...
is valid SQL, but
SELECT a.* FROM (my_table AS a JOIN your_table AS b ON ...) AS c
is not valid: the table alias a is not visible outside the alias c.
Subqueries specifying a derived table must be enclosed in parentheses and must be assigned a table alias name. (See Section 7.2.1.2.) For example:
FROM (SELECT * FROM table1) AS alias_name
This example is equivalent to FROM table1 AS alias_name. More interesting cases, which can't be reduced to a plain join, arise when the subquery involves grouping or aggregation.
Table functions are functions that produce a set of rows, made up of either base data types (scalar types) or composite data types (table rows). They are used like a table, view, or subquery in the FROM clause of a query. Columns returned by table functions may be included in SELECT, JOIN, or WHERE clauses in the same manner as a table, view, or subquery column.
If a table function returns a base data type, the single result column is named like the function. If the function returns a composite type, the result columns get the same names as the individual attributes of the type.
A table function may be aliased in the FROM clause, but it also may be left unaliased. If a function is used in the FROM clause with no alias, the function name is used as the resulting table name.
Some examples:
CREATE TABLE foo (fooid int, foosubid int, fooname text); CREATE FUNCTION getfoo(int) RETURNS SETOF foo AS $$ SELECT * FROM foo WHERE fooid = $1; $$ LANGUAGE SQL; SELECT * FROM getfoo(1) AS t1; SELECT * FROM foo WHERE foosubid IN (select foosubid from getfoo(foo.fooid) z where z.fooid = foo.fooid); CREATE VIEW vw_getfoo AS SELECT * FROM getfoo(1); SELECT * FROM vw_getfoo;
In some cases it is useful to define table functions that can return different column sets depending on how they are invoked. To support this, the table function can be declared as returning the pseudotype record. When such a function is used in a query, the expected row structure must be specified in the query itself, so that the system can know how to parse and plan the query. Consider this example:
SELECT * FROM dblink('dbname=mydb', 'select proname, prosrc from pg_proc') AS t1(proname name, prosrc text) WHERE proname LIKE 'bytea%';
The dblink function executes a remote query (see contrib/dblink). It is declared to return record since it might be used for any kind of query. The actual column set must be specified in the calling query so that the parser knows, for example, what * should expand to.
The syntax of the WHERE Clause is
WHERE search_condition
where search_condition is any value expression (see Section 4.2) that returns a value of type boolean.
After the processing of the FROM clause is done, each row of the derived virtual table is checked against the search condition. If the result of the condition is true, the row is kept in the output table, otherwise (that is, if the result is false or null) it is discarded. The search condition typically references at least some column of the table generated in the FROM clause; this is not required, but otherwise the WHERE clause will be fairly useless.
Note: The join condition of an inner join can be written either in the WHERE clause or in the JOIN clause. For example, these table expressions are equivalent:
FROM a, b WHERE a.id = b.id AND b.val > 5and
FROM a INNER JOIN b ON (a.id = b.id) WHERE b.val > 5or perhaps even
FROM a NATURAL JOIN b WHERE b.val > 5Which one of these you use is mainly a matter of style. The JOIN syntax in the FROM clause is probably not as portable to other SQL database management systems. For outer joins there is no choice in any case: they must be done in the FROM clause. An ON/USING clause of an outer join is not equivalent to a WHERE condition, because it determines the addition of rows (for unmatched input rows) as well as the removal of rows from the final result.
Here are some examples of WHERE clauses:
SELECT ... FROM fdt WHERE c1 > 5 SELECT ... FROM fdt WHERE c1 IN (1, 2, 3) SELECT ... FROM fdt WHERE c1 IN (SELECT c1 FROM t2) SELECT ... FROM fdt WHERE c1 IN (SELECT c3 FROM t2 WHERE c2 = fdt.c1 + 10) SELECT ... FROM fdt WHERE c1 BETWEEN (SELECT c3 FROM t2 WHERE c2 = fdt.c1 + 10) AND 100 SELECT ... FROM fdt WHERE EXISTS (SELECT c1 FROM t2 WHERE c2 > fdt.c1)
fdt is the table derived in the FROM clause. Rows that do not meet the search condition of the WHERE clause are eliminated from fdt. Notice the use of scalar subqueries as value expressions. Just like any other query, the subqueries can employ complex table expressions. Notice also how fdt is referenced in the subqueries. Qualifying c1 as fdt.c1 is only necessary if c1 is also the name of a column in the derived input table of the subquery. But qualifying the column name adds clarity even when it is not needed. This example shows how the column naming scope of an outer query extends into its inner queries.
After passing the WHERE filter, the derived input table may be subject to grouping, using the GROUP BY clause, and elimination of group rows using the HAVING clause.
SELECT select_list FROM ... [WHERE ...] GROUP BY grouping_column_reference [, grouping_column_reference]...
The GROUP BY Clause is used to group together those rows in a table that share the same values in all the columns listed. The order in which the columns are listed does not matter. The effect is to combine each set of rows sharing common values into one group row that is representative of all rows in the group. This is done to eliminate redundancy in the output and/or compute aggregates that apply to these groups. For instance:
=> SELECT * FROM test1; x | y ---+--- a | 3 c | 2 b | 5 a | 1 (4 rows) => SELECT x FROM test1 GROUP BY x; x --- a b c (3 rows)
In the second query, we could not have written SELECT * FROM test1 GROUP BY x, because there is no single value for the column y that could be associated with each group. The grouped-by columns can be referenced in the select list since they have a single value in each group.
In general, if a table is grouped, columns that are not used in the grouping cannot be referenced except in aggregate expressions. An example with aggregate expressions is:
=> SELECT x, sum(y) FROM test1 GROUP BY x; x | sum ---+----- a | 4 b | 5 c | 2 (3 rows)
Here sum is an aggregate function that computes a single value over the entire group. More information about the available aggregate functions can be found in Section 9.15.
Tip: Grouping without aggregate expressions effectively calculates the set of distinct values in a column. This can also be achieved using the DISTINCT clause (see Section 7.3.3).
Here is another example: it calculates the total sales for each product (rather than the total sales on all products).
SELECT product_id, p.name, (sum(s.units) * p.price) AS sales FROM products p LEFT JOIN sales s USING (product_id) GROUP BY product_id, p.name, p.price;
In this example, the columns product_id, p.name, and p.price must be in the GROUP BY clause since they are referenced in the query select list. (Depending on how exactly the products table is set up, name and price may be fully dependent on the product ID, so the additional groupings could theoretically be unnecessary, but this is not implemented yet.) The column s.units does not have to be in the GROUP BY list since it is only used in an aggregate expression (sum(...)), which represents the sales of a product. For each product, the query returns a summary row about all sales of the product.
In strict SQL, GROUP BY can only group by columns of the source table but PostgreSQL extends this to also allow GROUP BY to group by columns in the select list. Grouping by value expressions instead of simple column names is also allowed.
If a table has been grouped using a GROUP BY clause, but then only certain groups are of interest, the HAVING clause can be used, much like a WHERE clause, to eliminate groups from a grouped table. The syntax is:
SELECT select_list FROM ... [WHERE ...] GROUP BY ... HAVING boolean_expression
Expressions in the HAVING clause can refer both to grouped expressions and to ungrouped expressions (which necessarily involve an aggregate function).
Example:
=> SELECT x, sum(y) FROM test1 GROUP BY x HAVING sum(y) > 3; x | sum ---+----- a | 4 b | 5 (2 rows) => SELECT x, sum(y) FROM test1 GROUP BY x HAVING x < 'c'; x | sum ---+----- a | 4 b | 5 (2 rows)
Again, a more realistic example:
SELECT product_id, p.name, (sum(s.units) * (p.price - p.cost)) AS profit FROM products p LEFT JOIN sales s USING (product_id) WHERE s.date > CURRENT_DATE - INTERVAL '4 weeks' GROUP BY product_id, p.name, p.price, p.cost HAVING sum(p.price * s.units) > 5000;
In the example above, the WHERE clause is selecting rows by a column that is not grouped (the expression is only true for sales during the last four weeks), while the HAVING clause restricts the output to groups with total gross sales over 5000. Note that the aggregate expressions do not necessarily need to be the same in all parts of the query.