6.1.3. The FROM clause

The FROM clause specifies the source(s) from which the data are to be retrieved. In its simplest form, this is just a single table or view. But the source can also be a selectable stored procedure, a derived table or a common table expression. Multiple sources can be combined using various types of joins.

This section concentrates on single-source selects. Joins are discussed in a following section.

Syntax

  1. SELECT
  2. ...
  3. FROM <source>
  4. [<joins>]
  5. [...]
  6. <source> ::=
  7. { table
  8. | view
  9. | selectable-stored-procedure [(<args>)]
  10. | <derived-table>
  11. | <common-table-expression>
  12. } [[AS] alias]
  13. <derived-table> ::=
  14. (<select-statement>) [[AS] alias] [(<column-aliases>)]
  15. <common-table-expression> ::=
  16. WITH [RECURSIVE] <cte-def> [, <cte-def> ...]
  17. <select-statement>
  18. <cte-def> ::= name [(<column-aliases>)] AS (<select-statement>)
  19. <column-aliases> ::= column-alias [, column-alias ...]
Table 64. Arguments for the FROM Clause
ArgumentDescription

table

Name of a table

view

Name of a view

selectable-stored-procedure

Name of a selectable stored procedure

args

Selectable stored procedure arguments

derived table

Derived table query expression

cte-def

Common table expression (CTE) definition, including an “ad hoc” name

select-statement

Any SELECT statement

column-aliases

Alias for a column in a relation, CTE or derived table

name

The “ad hoc” name for a CTE

alias

The alias of a data source (table, view, procedure, CTE, derived table)

Selecting FROM a table or view

When selecting from a single table or view, the FROM clause need not contain anything more than the name. An alias may be useful or even necessary if there are subqueries that refer to the main select statement (as they often do — subqueries like this are called correlated subqueries).

Examples

  1. select id, name, sex, age from actors
  2. where state = 'Ohio'
  1. select * from birds
  2. where type = 'flightless'
  3. order by family, genus, species
  1. select firstname,
  2. middlename,
  3. lastname,
  4. date_of_birth,
  5. (select name from schools s where p.school = s.id) schoolname
  6. from pupils p
  7. where year_started = '2012'
  8. order by schoolname, date_of_birth
Never mix column names with column aliases!

If you specify an alias for a table or a view, you must always use this alias in place of the table name whenever you query the columns of the relation (and wherever else you make a reference to columns, such as ORDER BY, GROUP BY and WHERE clauses).

Correct use:

  1. SELECT PEARS
  2. FROM FRUIT;
  3. SELECT FRUIT.PEARS
  4. FROM FRUIT;
  5. SELECT PEARS
  6. FROM FRUIT F;
  7. SELECT F.PEARS
  8. FROM FRUIT F;

Incorrect use:

  1. SELECT FRUIT.PEARS
  2. FROM FRUIT F;

Selecting FROM a stored procedure

A selectable stored procedure is a procedure that:

  • contains at least one output parameter, and

  • utilizes the SUSPEND keyword so the caller can fetch the output rows one by one, just as when selecting from a table or view.

The output parameters of a selectable stored procedure correspond to the columns of a regular table.

Selecting from a stored procedure without input parameters is just like selecting from a table or view:

  1. select * from suspicious_transactions
  2. where assignee = 'John'

Any required input parameters must be specified after the procedure name, enclosed in parentheses:

  1. select name, az, alt from visible_stars('Brugge', current_date, '22:30')
  2. where alt >= 20
  3. order by az, alt

Values for optional parameters (that is, parameters for which default values have been defined) may be omitted or provided. However, if you provide them only partly, the parameters you omit must all be at the tail end.

Supposing that the procedure visible_stars from the previous example has two optional parameters: min_magn (numeric(3,1)) and spectral_class (varchar(12)), the following queries are all valid:

  1. select name, az, alt
  2. from visible_stars('Brugge', current_date, '22:30');
  3. select name, az, alt
  4. from visible_stars('Brugge', current_date, '22:30', 4.0);
  5. select name, az, alt
  6. from visible_stars('Brugge', current_date, '22:30', 4.0, 'G');

But this one isn’t, because there’s a “hole” in the parameter list:

  1. select name, az, alt
  2. from visible_stars('Brugge', current_date, '22:30', 'G');

An alias for a selectable stored procedure is specified after the parameter list:

  1. select
  2. number,
  3. (select name from contestants c where c.number = gw.number)
  4. from get_winners('#34517', 'AMS') gw

If you refer to an output parameter (“column”) by qualifying it with the full procedure name, the procedure alias should be omitted:

  1. select
  2. number,
  3. (select name from contestants c where c.number = get_winners.number)
  4. from get_winners('#34517', 'AMS')

See also

Stored Procedures, CREATE PROCEDURE

Selecting FROM a derived table

A derived table is a valid SELECT statement enclosed in parentheses, optionally followed by a table alias and/or column aliases. The result set of the statement acts as a virtual table which the enclosing statement can query.

Syntax

  1. (<select-query>)
  2. [[AS] derived-table-alias]
  3. [(<derived-column-aliases>)]
  4. <derived-column-aliases> := column-alias [, column-alias ...]

The set returned data set by this “SELECT FROM (SELECT FROM..)” style of statement is a virtual table that can be queried within the enclosing statement, as if it were a regular table or view.

Sample using a derived table

The derived table in the query below returns the list of table names in the database and the number of columns in each. A “drill-down” query on the derived table returns the counts of fields and the counts of tables having each field count:

  1. SELECT
  2. FIELDCOUNT,
  3. COUNT(RELATION) AS NUM_TABLES
  4. FROM (SELECT
  5. R.RDB$RELATION_NAME RELATION,
  6. COUNT(*) AS FIELDCOUNT
  7. FROM RDB$RELATIONS R
  8. JOIN RDB$RELATION_FIELDS RF
  9. ON RF.RDB$RELATION_NAME = R.RDB$RELATION_NAME
  10. GROUP BY RELATION)
  11. GROUP BY FIELDCOUNT

A trivial example demonstrating how the alias of a derived table and the list of column aliases (both optional) can be used:

  1. SELECT
  2. DBINFO.DESCR, DBINFO.DEF_CHARSET
  3. FROM (SELECT *
  4. FROM RDB$DATABASE) DBINFO
  5. (DESCR, REL_ID, SEC_CLASS, DEF_CHARSET)
More about Derived Tables

Derived tables can

  • be nested

  • be unions, and can be used in unions

  • contain aggregate functions, subqueries and joins

  • be used in aggregate functions, subqueries and joins

  • be calls to selectable stored procedures or queries to them

  • have WHERE, ORDER BY and GROUP BY clauses, FIRST/SKIP or ROWS directives, et al.

Furthermore,

  • Each column in a derived table must have a name. If it does not have a name, such as when it is a constant or a run-time expression, it should be given an alias, either in the regular way or by including it in the list of column aliases in the derived table’s specification.

    • The list of column aliases is optional but, if it exists, it must contain an alias for every column in the derived table

  • The optimizer can process derived tables very effectively. However, if a derived table is included in an inner join and contains a subquery, the optimizer will be unable to use any join order.

A more useful example

Suppose we have a table COEFFS which contains the coefficients of a number of quadratic equations we have to solve. It has been defined like this:

  1. create table coeffs (
  2. a double precision not null,
  3. b double precision not null,
  4. c double precision not null,
  5. constraint chk_a_not_zero check (a <> 0)
  6. )

Depending on the values of a, b and c, each equation may have zero, one or two solutions. It is possible to find these solutions with a single-level query on table COEFFS, but the code will look rather messy and several values (like the discriminant) will have to be calculated multiple times per row. A derived table can help keep things clean here:

  1. select
  2. iif (D >= 0, (-b - sqrt(D)) / denom, null) sol_1,
  3. iif (D > 0, (-b + sqrt(D)) / denom, null) sol_2
  4. from
  5. (select b, b*b - 4*a*c, 2*a from coeffs) (b, D, denom)

If we want to show the coefficients next to the solutions (which may not be a bad idea), we can alter the query like this:

  1. select
  2. a, b, c,
  3. iif (D >= 0, (-b - sqrt(D)) / denom, null) sol_1,
  4. iif (D > 0, (-b + sqrt(D)) / denom, null) sol_2
  5. from
  6. (select a, b, c, b*b - 4*a*c as D, 2*a as denom
  7. from coeffs)

Notice that whereas the first query used a column aliases list for the derived table, the second adds aliases internally where needed. Both methods work, as long as every column is guaranteed to have a name.

Selecting FROM a CTE

A common table expression or CTE is a more complex variant of the derived table, but it is also more powerful. A preamble, starting with the keyword WITH, defines one or more named CTE‘s, each with an optional column aliases list. The main query, which follows the preamble, can then access these CTE‘s as if they were regular tables or views. The CTE‘s go out of scope once the main query has run to completion.

For a full discussion of CTE‘s, please refer to the section Common Table Expressions (WITH …​ AS …​ SELECT).

The following is a rewrite of our derived table example as a CTE:

  1. with vars (b, D, denom) as (
  2. select b, b*b - 4*a*c, 2*a from coeffs
  3. )
  4. select
  5. iif (D >= 0, (-b - sqrt(D)) / denom, null) sol_1,
  6. iif (D > 0, (-b + sqrt(D)) / denom, null) sol_2
  7. from vars

Except for the fact that the calculations that have to be made first are now at the beginning, this isn’t a great improvement over the derived table version. But we can now also eliminate the double calculation of sqrt(D) for every row:

  1. with vars (b, D, denom) as (
  2. select b, b*b - 4*a*c, 2*a from coeffs
  3. ),
  4. vars2 (b, D, denom, sqrtD) as (
  5. select b, D, denom, iif (D >= 0, sqrt(D), null) from vars
  6. )
  7. select
  8. iif (D >= 0, (-b - sqrtD) / denom, null) sol_1,
  9. iif (D > 0, (-b + sqrtD) / denom, null) sol_2
  10. from vars2

The code is a little more complicated now, but it might execute more efficiently (depending on what takes more time: executing the SQRT function or passing the values of b, D and denom through an extra CTE). Incidentally, we could have done the same with derived tables, but that would involve nesting.

See also

Common Table Expressions (WITH …​ AS …​ SELECT).