All pages
Powered by GitBook
1 of 35

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Selecting Data

Learn to select data in MariaDB Server using SQL. This section covers various SELECT statement clauses, including WHERE, GROUP BY, and ORDER BY, to retrieve and filter your data effectively.

DUAL

Understand the DUAL table. This dummy table allows selecting values without referencing a real table, often used for calculations or retrieving system variables.

Description

You can use DUAL instead of a table name in situations where no tables are referenced, such as the following SELECT statement:

SELECT 1 + 1 FROM DUAL;
+-------+
| 1 + 1 |
+-------+
|     2 |
+-------+

DUAL is purely for the convenience of people who require that all SELECT statements should haveFROM and possibly other clauses. MariaDB ignores the clauses. MariaDB does not require FROM DUAL if no tables are referenced.

FROM DUAL could be used when you only SELECT computed values, but require a WHERE clause, perhaps to test that a script correctly handles empty resultsets:

See Also

This page is licensed: GPLv2, originally from

Subqueries and EXISTS

Test for the existence of rows. The EXISTS operator returns TRUE if the subquery returns at least one row, often used for correlated subqueries.

Syntax

Description

using the EXISTS

Scalar Subqueries

Return a single value. A scalar subquery produces a one-row, one-column result that can be used anywhere a constant or expression is valid.

A scalar subquery is a that returns a single value. This is the simplest form of a subquery, and can be used in most places a literal or single column value is valid.

The data type, length and are all taken from the result returned by the subquery. The result of a subquery can always be NULL, that is, no result returned. Even if the original value is defined as NOT NULL, this is disregarded.

A subquery cannot be used where only a literal is expected, for example expects a literal string containing the file name, and LIMIT requires a literal integer.

Examples

Inserting a second row means the subquery is no longer a scalar, and this particular query is not valid:

SELECT INTO DUMPFILE

Export a single row to a file without formatting. This statement writes raw binary data, such as BLOBs, directly to a file on the server.

Syntax

Description

SELECT ... INTO DUMPFILE

Common Table Expressions (CTE)

Learn about Common Table Expressions (CTEs) in MariaDB Server. This section explains how to use CTEs for complex, readable, and reusable subqueries, simplifying data selection and manipulation.

Set Operations

SQL set operations combine the results of multiple query blocks in a single result, using the standard SQL operators EXCEPT, INTERSECT, and UNION, and the Oracle operator MINUS.

keyword will return
true
if the subquery returns any rows. Conversely, subqueries using
NOT EXISTS
will return
true
only if the subquery returns no rows from the table.

EXISTS subqueries ignore the columns specified by the SELECT of the subquery, since they're not relevant. For example,

and

produce identical results.

Examples

This page is licensed: CC BY-SA / Gnu FDL

SELECT ... WHERE EXISTS <Table subquery>
Subqueries
SELECT col1 FROM t1 WHERE EXISTS (SELECT * FROM t2);

No rows in the subquery, so the scalar is NULL:

A more traditional scalar subquery, as part of a WHERE clause:

This page is licensed: CC BY-SA / Gnu FDL

CREATE TABLE sq1 (num TINYINT);

CREATE TABLE sq2 (num TINYINT);

INSERT INTO sq1 VALUES (1);

INSERT INTO sq2 VALUES (10* (SELECT num FROM sq1));

SELECT * FROM sq2;
+------+
| num  |
+------+
|   10 |
+------+
subquery
character set and collation
LOAD DATA INFILE
INSERT INTO sq1 VALUES (2);

INSERT INTO sq2 VALUES (10* (SELECT num FROM sq1));
ERROR 1242 (21000): Subquery returns more than 1 row
is a
clause which writes the resultset into a single unformatted row, without any separators, in a file. The results will not be returned to the client.

file_path can be an absolute path, or a relative path starting from the data directory. It can only be specified as a string literal, not as a variable. However, the statement can be dynamically composed and executed as a prepared statement to work around this limitation.

This statement is binary-safe and so is particularly useful for writing BLOB values to file. It can be used, for example, to copy an image or an audio document from the database to a file.

The file must not exist. It cannot be overwritten. A user needs the FILE privilege to run this statement. Also, MariaDB needs permission to write files in the specified location. If the secure_file_priv system variable is set to a non-empty directory name, the file can only be written to that directory.

The character_set_filesystem system variable has controlled interpretation of file names that are given as literal strings.

The character_set_filesystem system variable does not have controlled interpretation of file names that are given as literal strings.

Example

See Also

  • SELECT

  • LOAD_FILE()

  • SELECT INTO Variable

  • SELECT INTO OUTFILE

This page is licensed: CC BY-SA / Gnu FDL

SELECT
SELECT 1 FROM DUAL WHERE FALSE;
Empty set (0.00 sec)
SELECT
fill_help_tables.sql

Subqueries in a FROM Clause (Derived Tables)

Use a subquery as a temporary table. Derived tables allow you to select from the result set of another query within the FROM clause.

Although subqueries are more commonly placed in a WHERE clause, they can also form part of the FROM clause. Such subqueries are commonly called derived tables.

If a subquery is used in this way, you must also use an AS clause to name the result of the subquery.

ORACLE mode

MariaDB starting with

(no AS clause) are permitted in .

(no AS clause) are not permitted in .

Correlation Column List

MariaDB starting with

It is possible to assign column names in the derived table name syntax element.

It is not possible to assign column names in the derived table name syntax element.

Examples

Assume that, given the data above, you want to return the average total for all students. In other words, the average of Chun's 148 (75+73), Esben's 74 (43+31), etc.

You cannot do the following:

A subquery in the FROM clause is however permitted:

The following is permitted:

In this example, the second column of the derived table dt is used both within (WHERE c2 > 0), and outside, (WHERE a2 > 10), the specification. Both conditions apply to t1.c2.

This page is licensed: CC BY-SA / Gnu FDL

FOR UPDATE

Lock rows for write operations. This clause prevents other transactions from modifying or reading the selected rows until the current transaction ends.

InnoDB supports row-level locking. Selected rows can be locked using LOCK IN SHARE MODE or FOR UPDATE. In both cases, a lock is acquired on the rows read by the query, and it will be released when the current transaction is committed.

The FOR UPDATE clause of SELECT applies only when autocommit is set to 0 or the SELECT is enclosed in a transaction. A lock is acquired on the rows, and other transactions are prevented from writing the rows, acquire locks, and from reading them (unless their isolation level is READ UNCOMMITTED).

If autocommit is set to 1, the LOCK IN SHARE MODE and FOR UPDATE clauses have no effect in InnoDB. For non-transactional storage engines like MyISAM and ARIA, a table level lock will be taken even if autocommit is set to 1.

If the isolation level is set to SERIALIZABLE, all plain SELECT statements are converted to SELECT ... LOCK IN SHARE MODE.

Example

See Also

This page is licensed: CC BY-SA / Gnu FDL

SELECT INTO OUTFILE

Export query results to a text file. This statement writes rows to a file on the server, allowing customization of field and line terminators.

Syntax

Description

SELECT INTO OUTFILE writes the resulting rows to a file, and allows the use of column and row terminators to specify a particular output format. The default is to terminate fields with tabs () and lines with newlines ().

The file must not exist. It cannot be overwritten. A user needs the privilege to run this statement. Also, MariaDB needs permission to write files in the specified location. If the system variable is set to a non-empty directory name, the file can only be written to that directory.

The statement complements SELECT INTO OUTFILE.

Character Sets

The CHARACTER SET clause specifies the in which the results are to be written. Without the clause, no conversion takes place (the binary character set). In this case, if there are multiple character sets, the output will contain these too, and may not easily be able to be reloaded.

In cases where you have two servers using different character-sets, using SELECT INTO OUTFILE to transfer data from one to the other can have unexpected results. To ensure that MariaDB correctly interprets the escape sequences, use the CHARACTER SET clause on both the SELECT INTO OUTFILE statement and the subsequent statement.

Example

The following example produces a file in the CSV format:

The following ANSI syntax is also supported for simple SELECT without UNION :

If you want to use the ANSI syntax with UNION or similar construct you have to use the syntax:

See Also

  • function

This page is licensed: CC BY-SA / Gnu FDL

Joins

Retrieve data from multiple tables based on related columns. This section covers INNER, LEFT, RIGHT, and CROSS JOIN syntax and usage.

JOIN Syntax

Main JOIN page, documenting all join types available in MariaDB.

Joining Tables with JOIN Clauses

Introduction to joining tables in MariaDB.

Introduction to advanced joins in MariaDB.

How to use a comma instead of a JOIN clause, and why you should always prefer the latter.

PROCEDURE

Pass query results to a C procedure. This clause allows processing the result set on the server side before returning it to the client.

The PROCEDURE clause of SELECT passes the whole result set to a Procedure which will process it. These Procedures are not Stored Procedures, and can only be written in the C language, so it is necessary to recompile the server.

Currently, the only available procedure is ANALYSE, which examines the resultset and suggests the optimal datatypes for each column. It is defined in the sql/sql_analyse.cc file, and can be used as an example to create more Procedures.

This clause cannot be used in a view definition.

See Also

This page is licensed: CC BY-SA / Gnu FDL

SELECT ... OFFSET ... FETCH

Pagination using standard SQL syntax. This clause limits the number of rows returned and skips a specified number of rows, similar to LIMIT.

SELECT ... OFFSET ... FETCH is available from .

Syntax

LOCK IN SHARE MODE

Read rows with a shared lock. This clause ensures rows remain unchanged by other transactions while allowing other sessions to read them.

InnoDB supports row-level locking. Selected rows can be locked using LOCK IN SHARE MODE or . In both cases, a lock is acquired on the rows read by the query, and it will be released when the current transaction is committed.

When LOCK IN SHARE MODE is specified in a statement, MariaDB will wait until all transactions that have modified the rows are committed. Then, a write lock is acquired. All transactions can read the rows, but if they want to modify them, they have to wait until your transaction is committed.

If is set to 1 (the default), the LOCK IN SHARE MODE and clauses have no effect in InnoDB. For non-transactional storage engines like MyISAM and ARIA, a table level lock will be taken even if autocommit is set to 1.

Precedence Control in Table Operations

Control the execution order of UNION, EXCEPT, and INTERSECT operations. Learn how to use parentheses to define explicit operation priority.

You can control the ordering of execution on table operations using parentheses.

Syntax

Description

MINUS

Oracle-compatible synonym for the EXCEPT operator. It returns rows from the first query that are not present in the second query.

MINUS is available starting from MariaDB 10.6.1.

MINUS is a synonym for when is set.

This page is licensed: CC BY-SA / Gnu FDL

SELECT col1 FROM t1 WHERE EXISTS (SELECT col2 FROM t2);
CREATE TABLE sq1 (num TINYINT);

CREATE TABLE sq2 (num2 TINYINT);

INSERT INTO sq1 VALUES(100);

INSERT INTO sq2 VALUES(40),(50),(60);

SELECT * FROM sq1 WHERE EXISTS (SELECT * FROM sq2 WHERE num2>50);
+------+
| num  |
+------+
|  100 |
+------+

SELECT * FROM sq1 WHERE NOT EXISTS (SELECT * FROM sq2 GROUP BY num2 HAVING MIN(num2)=40);
Empty set (0.00 sec)
INSERT INTO sq2 VALUES (10* (SELECT num FROM sq3 WHERE num='3'));

SELECT * FROM sq2;
+------+
| num  |
+------+
|   10 |
| NULL |
+------+
SELECT * FROM sq1 WHERE num = (SELECT MAX(num)/10 FROM sq2); 
+------+
| num  |
+------+
|    1 |
+------+
SELECT ... INTO DUMPFILE 'file_path'
SELECT _utf8'Hello world!' INTO DUMPFILE '/tmp/world';

SELECT LOAD_FILE('/tmp/world') AS world;
+--------------+
| world        |
+--------------+
| Hello world! |
+--------------+
SELECT ... INTO OUTFILE 'file_name'
        [CHARACTER SET charset_name]
        [export_options]

export_options:
    [{FIELDS | COLUMNS}
        [TERMINATED BY 'string']
        [[OPTIONALLY] ENCLOSED BY 'char']
        [ESCAPED BY 'char']
    ]
    [LINES
        [STARTING BY 'string']
        [TERMINATED BY 'string']
    ]
Advanced Joins
Comma vs JOIN

Subqueries

Nest queries within other SQL statements. Learn to use scalar, column, row, and table subqueries to filter or calculate data dynamically.

SELECT INTO DUMPFILE
FILE
secure_file_priv
LOAD DATA INFILE
character set
LOAD DATA INFILE
SELECT
LOAD_DATA()
LOAD DATA INFILE
SELECT INTO Variable
Description

The OFFSET clause allows one to return only those elements of a resultset that come after a specified offset. The FETCH clause specifies the number of rows to return, while ONLY or WITH TIES specifies whether or not to also return any further results that tie for last place according to the ordered resultset.

Either the singular ROW or the plural ROWS can be used after the OFFSET and FETCH clauses; the choice has no impact on the results.

FIRST and NEXT give the same result.

In the case of WITH TIES, an ORDER BY clause is required, otherwise an error will be returned.

Examples

Given a table with 6 rows:

OFFSET 2 allows one to skip the first two results:

FETCH FIRST 3 ROWS ONLY limits the results to three rows only:

The same outcome can also be achieved with the LIMIT clause:

WITH TIES ensures the tied result 4 is also returned:

See Also

  • LIMIT

  • ORDER BY

  • SELECT

This page is licensed: CC BY-SA / Gnu FDL

MariaDB 10.6
See Also
  • SELECT

  • FOR UPDATE

  • InnoDB Lock Modes

This page is licensed: CC BY-SA / Gnu FDL

FOR UPDATE
SELECT
autocommit
FOR UPDATE
Using parentheses in SQL allows to control the order of execution for SELECT statements and Table Value Constructor, including UNION, EXCEPT, and INTERSECT operations. MariaDB executes the parenthetical expression before the rest of the statement. You can then use ORDER BY and LIMIT clauses the further organize the result set.

The Optimizer may rearrange the exact order in which MariaDB executes different parts of the statement. When it calculates the result set, however, it returns values as though the parenthetical expression were executed first.

Example

This page is licensed: CC BY-SA / Gnu FDL

Anonymous subqueries in a FROM clause
SELECT
LOCK IN SHARE MODE
InnoDB Lock Modes
CREATE TABLE seqs (i INT);
INSERT INTO seqs VALUES (1),(2),(2),(3),(3),(4),(5),(6);

SET SQL_MODE='ORACLE';

SELECT i FROM seqs WHERE i <= 3 MINUS SELECT i FROM seqs WHERE i>=3;
+------+
| i    |
+------+
|    1 |
|    2 |
+------+
EXCEPT
SELECT
Stored Procedures

GROUP BY

Group result sets by one or more columns. Learn to aggregate data using functions like SUM, COUNT, and AVG in conjunction with grouping.

Use the GROUP BY clause in a SELECT statement to group rows together that have the same value in one or more column, or the same computed value using expressions with any functions and operators except grouping functions. When you use a GROUP BY clause, you will get a single result row for each group of rows that have the same value for the expression given in GROUP BY.

When grouping rows, grouping values are compared as if by the = operator. For string values, the = operator ignores trailing whitespace and may normalize characters and ignore case, depending on the collation in use.

You can use any of the grouping functions in your select expression. Their values will be calculated based on all the rows that have been grouped together for each result row. If you select a non-grouped column or a value computed from a non-grouped column, it is undefined which row the returned value is taken from. This is not permitted if the ONLY_FULL_GROUP_BY is used.

You can use multiple expressions in the GROUP BY clause, separated by commas. Rows are grouped together if they match on each of the expressions.

You can also use a single integer as the grouping expression. If you use an integer n, the results will be grouped by the _n_th column in the select expression.

The WHERE clause is applied before the GROUP BY clause. It filters non-aggregated rows before the rows are grouped together. To filter grouped rows based on aggregate values, use the HAVING clause. The HAVING clause takes any expression and evaluates it as a boolean, just like the WHERE clause. You can use grouping functions in the HAVING clause. As with the select expression, if you reference non-grouped columns in the HAVING clause, the behavior is undefined.

By default, if a GROUP BY clause is present, the rows in the output will be sorted by the expressions used in the GROUP BY. You can also specify ASC or DESC (ascending, descending) after those expressions, like in . The default is ASC.

If you want the rows to be sorted by another field, you can add an explicit . If you don't want the result to be ordered, you can add .

WITH ROLLUP

The WITH ROLLUP modifier adds extra rows to the result set that represent super-aggregate summaries. For a full description with examples, see .

GROUP BY Examples

Consider the following table that records how many times each user has played and won a game:

Get a list of win counts along with a count:

The GROUP BY expression can be a computed value, and can refer back to an identifier specified with AS. Get a list of win averages along with a count:

You can use any in the select expression. For each win average as above, get a list of the average play count taken to get that average:

You can filter on aggregate information using the HAVING clause. The HAVING clause is applied after GROUP BY and allows you to filter on aggregate data that is not available to the WHERE clause. Restrict the above example to results that involve an average number of plays over 20:

See Also

This page is licensed: CC BY-SA / Gnu FDL

WITH

Define one or more Common Table Expressions (CTEs). The WITH clause starts a statement by declaring named temporary result sets that can be referenced in the main query.

Syntax

Description

The WITH

Non-Recursive Common Table Expressions Overview

Define simple temporary result sets. Non-recursive CTEs act like query-local views, improving readability by allowing you to define and reuse subqueries within a single statement.

Common Table Expressions (CTEs) are a standard SQL feature, and are essentially temporary named result sets. There are two kinds of CTEs: Non-Recursive, which this article covers; and .

Non-Recursive CTEs

The keyword signifies a CTE. It is given a name, followed by a body (the main query).

CTEs are similar to derived tables:

A non-recursive CTE is basically a query-local . There are several advantages and caveats to them. The syntax is more readable than a nested FROM (SELECT ...)

SELECT customer_id, firstname, surname FROM customer
  INTO OUTFILE '/exportdata/customers.txt'
  FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
  LINES TERMINATED BY '\n';
SELECT customer_id, firstname, surname INTO OUTFILE '/exportdata/customers.txt'
  FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
  LINES TERMINATED BY '\n'
  FROM customers;
SELECT  * INTO OUTFILE "/tmp/skr3" 
FROM (SELECT * FROM t1 UNION SELECT * FROM t1);
OFFSET start { ROW | ROWS }
FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } { ONLY | WITH TIES }
SELECT i FROM t1 FETCH FIRST 2 ROWS WITH TIES;
ERROR 4180 (HY000): FETCH ... WITH TIES requires ORDER BY clause to be present
CREATE OR REPLACE TABLE t1 (i INT);
INSERT INTO t1 VALUES (1),(2),(3),(4), (4), (5);
SELECT i FROM t1 ORDER BY i ASC;
+------+
| i    |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
|    4 |
|    5 |
+------+
SELECT i FROM t1 ORDER BY i ASC OFFSET 2 ROWS;
+------+
| i    |
+------+
|    3 |
|    4 |
|    4 |
|    5 |
+------+
SELECT i FROM t1 ORDER BY i ASC OFFSET 1 ROWS FETCH FIRST 3 ROWS ONLY;
+------+
| i    |
+------+
|    2 |
|    3 |
|    4 |
+------+
SELECT i FROM t1 ORDER BY i ASC LIMIT 3 OFFSET 1;
+------+
| i    |
+------+
|    2 |
|    3 |
|    4 |
+------+
SELECT i FROM t1 ORDER BY i ASC OFFSET 1 ROWS FETCH FIRST 3 ROWS WITH TIES;
+------+
| i    |
+------+
|    2 |
|    3 |
|    4 |
|    4 |
+------+
(  expression )
[ORDER BY [column[, column...]]]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
CREATE TABLE test.t1 (num INT);

INSERT INTO test.t1 VALUES (1),(2),(3);

(SELECT * FROM test.t1 
 UNION 
 VALUES (10)) 
INTERSECT 
VALUES (1),(3),(10),(11);
+------+
| num  |
+------+
|    1 |
|    3 |
|   10 |
+------+

((SELECT * FROM test.t1 
  UNION 
  VALUES (10)) 
 INTERSECT 
 VALUES (1),(3),(10),(11)) 
ORDER BY 1 DESC;
+------+
| num  |
+------+
|   10 |
|    3 |
|    1 |
+------+
CREATE TABLE student (name CHAR(10), test CHAR(10), score TINYINT); 

INSERT INTO student VALUES 
  ('Chun', 'SQL', 75), ('Chun', 'Tuning', 73), 
  ('Esben', 'SQL', 43), ('Esben', 'Tuning', 31), 
  ('Kaolin', 'SQL', 56), ('Kaolin', 'Tuning', 88), 
  ('Tatiana', 'SQL', 87), ('Tatiana', 'Tuning', 83);
SELECT AVG(SUM(score)) FROM student GROUP BY name;
ERROR 1111 (HY000): Invalid use of group function
SELECT AVG(sq_sum) FROM (SELECT SUM(score) AS sq_sum FROM student GROUP BY name) AS t;
+-------------+
| AVG(sq_sum) |
+-------------+
|    134.0000 |
+-------------+
SELECT * FROM (SELECT 1 FROM DUAL), (SELECT 2 FROM DUAL);
CREATE OR REPLACE TABLE t1(c1 INT, c2 INT, c3 INT);

SELECT a1, a2 FROM (SELECT c1, c2, c3 FROM t1 WHERE c2 > 0) AS dt (a1, a2, a3);
SELECT * FROM trans WHERE period=2001 FOR UPDATE;
Common Table Expressions
  • SELECT WITH ROLLUP

  • SELECT INTO OUTFILE

  • SELECT INTO DUMPFILE

  • FOR UPDATE

  • LOCK IN SHARE MODE

  • Optimizer Hints

  • SQL_MODE
    ORDER BY
    ORDER BY
    ORDER BY NULL
    SELECT WITH ROLLUP
    grouping function
    SELECT
    Joins and Subqueries
    LIMIT
    ORDER BY
    . A CTE can refer to another and it can be referenced from multiple places.

    A CTE referencing Another CTE

    Using this format makes for a more readable SQL than a nested FROM(SELECT ...) clause:

    Multiple Uses of a CTE

    This can be an 'anti-self join', for example:

    Or, for year-over-year comparisons, for example:

    Another use is to compare individuals against their group. Below is an example of how this might be executed:

    This page is licensed: CC BY-SA / Gnu FDL

    WITH engineers AS 
       ( SELECT * FROM employees
         WHERE dept = 'Engineering' )
    
    SELECT * FROM engineers
    WHERE ...
    Recursive
    WITH
    VIEW
    CREATE TABLE plays (name VARCHAR(16), plays INT, wins INT);
    INSERT INTO plays VALUES 
      ("John", 20, 5), 
      ("Robert", 22, 8), 
      ("Wanda", 32, 8), 
      ("Susan", 17, 3);
    SELECT wins, COUNT(*) FROM plays GROUP BY wins;
    +------+----------+
    | wins | COUNT(*) |
    +------+----------+
    |    3 |        1 |
    |    5 |        1 |
    |    8 |        2 |
    +------+----------+
    3 rows in set (0.00 sec)
    SELECT (wins / plays) AS winavg, COUNT(*) FROM plays GROUP BY winavg;
    +--------+----------+
    | winavg | COUNT(*) |
    +--------+----------+
    | 0.1765 |        1 |
    | 0.2500 |        2 |
    | 0.3636 |        1 |
    +--------+----------+
    3 rows in set (0.00 sec)
    SELECT (wins / plays) AS winavg, AVG(plays) FROM plays 
      GROUP BY winavg;
    +--------+------------+
    | winavg | AVG(plays) |
    +--------+------------+
    | 0.1765 |    17.0000 |
    | 0.2500 |    26.0000 |
    | 0.3636 |    22.0000 |
    +--------+------------+
    3 rows in set (0.00 sec)
    SELECT (wins / plays) AS winavg, AVG(plays) FROM plays 
      GROUP BY winavg HAVING AVG(plays) > 20;
    +--------+------------+
    | winavg | AVG(plays) |
    +--------+------------+
    | 0.2500 |    26.0000 |
    | 0.3636 |    22.0000 |
    +--------+------------+
    2 rows in set (0.00 sec)
    SELECT * FROM
       ( SELECT * FROM employees
         WHERE dept = 'Engineering' ) AS engineers
    WHERE
    ...
    WITH engineers AS (
    SELECT * FROM employees
    WHERE dept IN('Development','Support') ),
    eu_engineers AS ( SELECT * FROM engineers WHERE country IN('NL',...) )
    SELECT
    ...
    FROM eu_engineers;
    WITH engineers AS (
    SELECT * FROM employees
    WHERE dept IN('Development','Support') )
    
    SELECT * FROM engineers E1
    WHERE NOT EXISTS
       (SELECT 1 FROM engineers E2
        WHERE E2.country=E1.country
        AND E2.name <> E1.name );
    WITH sales_product_year AS (
    SELECT product, YEAR(ship_date) AS year,
    SUM(price) AS total_amt
    FROM item_sales
    GROUP BY product, year )
    
    SELECT *
    FROM sales_product_year CUR,
    sales_product_year PREV,
    WHERE CUR.product=PREV.product 
    AND  CUR.year=PREV.year + 1 
    AND CUR.total_amt > PREV.total_amt
    WITH sales_product_year AS (
    SELECT product,
    YEAR(ship_date) AS year,
    SUM(price) AS total_amt
    FROM item_sales
    GROUP BY product, year
    )
    
    SELECT * 
    FROM sales_product_year S1
    WHERE
    total_amt > 
        (SELECT 0.1 * SUM(total_amt)
         FROM sales_product_year S2
         WHERE S2.year = S1.year)
    keyword signifies a
    (CTE). It allows you to refer to a subquery expression many times in a query, as if having a temporary table that only exists for the duration of a query.

    There are two kinds of CTEs:

    • Non-Recursive.

    • Recursive (signified by the RECURSIVE keyword).

    You can use table_reference as any normal table in the external SELECT part. You can also use WITH in subqueries, as well as with EXPLAIN and SELECT.

    Poorly-formed recursive CTEs can in theory cause infinite loops. The max_recursive_iterations system variable limits the number of recursions.

    CYCLE ... RESTRICT

    The CYCLE clause enables CTE cycle detection, avoiding excessive or infinite loops, MariaDB supports a relaxed, non-standard grammar. The SQL Standard permits a CYCLE clause, as follows:

    WITH RECURSIVE ... (
      ...
    )
    CYCLE <cycle column list>
    SET <cycle mark column> TO <cycle mark value> DEFAULT <non-cycle mark value>
    USING 

    where all clauses are mandatory. MariaDB does not support this, but permits a non-standard relaxed grammar, as follows:

    WITH RECURSIVE ... (
      ...
    )
    CYCLE <cycle column list> RESTRICT

    With the use of CYCLE ... RESTRICT it makes no difference whether the CTE uses UNION ALL or UNION DISTINCT anymore. UNION ALL means "all rows, but without cycles", which is exactly what the CYCLE clause enables. And UNION DISTINCT means all rows should be different, which, again, is what will happen — as uniqueness is enforced over a subset of columns, complete rows will automatically all be different.

    CYCLE ... RESTRICT is not available.

    Examples

    Below is an example with the WITH at the top level:

    The example below uses WITH in a subquery:

    Below is an example of a Recursive CTE:

    Consider the following structure and data:

    Given the above, the following query would theoretically result in an infinite loop due to the last record in t1 (note that max_recursive_iterations is set to 10 for the purposes of this example, to avoid the excessive number of cycles):

    However, the CYCLE ... RESTRICT clause can overcome this:

    See Also

    • Non-Recursive Common Table Expressions Overview

    • Recursive Common Table Expressions Overview

    This page is licensed: CC BY-SA / Gnu FDL

    Common Table Expression

    Subqueries and ALL

    Compare a value against all results from a subquery. The ALL operator returns TRUE if the comparison holds for every row returned by the subquery.

    Subqueries using the ALL keyword will return true if the comparison returns true for each row returned by the subquery, or the subquery returns no rows.

    Syntax

    • scalar_expression may be any expression that evaluates to a single value.

    • comparison_operator may be any one of: =, >, <, >=, <=, <> or !=

    ALL returns:

    • NULL if the comparison operator returns NULL for at least one row returned by the Table subquery or scalar_expression returns NULL.

    • FALSE if the comparison operator returns FALSE for at least one row returned by the Table subquery.

    NOT IN is an alias for <> ALL.

    Examples

    Since 100 > all of 40,50 and 60, the evaluation is true and the row is returned.

    Adding a second row to sq1, where the evaluation for that record is false:

    Adding a new row to sq2, causing all evaluations to be false:

    When the subquery returns no results, the evaluation is still true:

    Evaluating against a NULL will cause the result to be unknown, or not true, and therefore return no rows:

    This page is licensed: CC BY-SA / Gnu FDL

    ORDER BY

    Sort query results. This clause arranges the returned rows in ascending or descending order based on specified columns or expressions.

    Description

    Use the ORDER BY clause to order a resultset, such as that are returned from a statement. You can specify just a column or use any expression with functions. If you are using the GROUP BY clause, you can use grouping functions in ORDER BY. Ordering is done after grouping.

    You can use multiple ordering expressions, separated by commas. Rows are sorted by the first expression, then by the second expression if they have the same value for the first, and so on.

    Row Subqueries

    Retrieve a single row of multiple values. A row subquery returns a tuple that can be compared against a row constructor in the outer query.

    A row subquery is a returning a single row, as opposed to a , which returns a single column from a row, or a literal.

    Examples

    Finding all rows in one table and also in another:

    This page is licensed: CC BY-SA / Gnu FDL

    WITH [RECURSIVE] table_reference [(columns_list)] AS  (
      SELECT ...
    )
    [CYCLE cycle_column_list RESTRICT]
    SELECT ...
    WITH t AS (SELECT a FROM t1 WHERE b >= 'c') 
      SELECT * FROM t2, t WHERE t2.c = t.a;
    SELECT t1.a, t1.b FROM t1, t2
      WHERE t1.a > t2.c 
         AND t2.c IN(WITH t AS (SELECT * FROM t1 WHERE t1.a < 5)
                    SELECT t2.c FROM t2, t WHERE t2.c = t.a);
    WITH RECURSIVE ancestors AS 
     ( SELECT * FROM folks
       WHERE name="Alex"
       UNION
       SELECT f.*
       FROM folks AS f, ancestors AS a
       WHERE f.id = a.father OR f.id = a.mother )
    SELECT * FROM ancestors;
    CREATE TABLE t1 (from_ int, to_ int);
    INSERT INTO t1 VALUES (1,2), (1,100), (2,3), (3,4), (4,1);
    SELECT * FROM t1;
    +-------+------+
    | from_ | to_  |
    +-------+------+
    |     1 |    2 |
    |     1 |  100 |
    |     2 |    3 |
    |     3 |    4 |
    |     4 |    1 |
    +-------+------+
    SET max_recursive_iterations=10;
    
    WITH RECURSIVE cte (depth, from_, to_) AS ( 
      SELECT 0,1,1 UNION DISTINCT SELECT depth+1, t1.from_, t1.to_ 
        FROM t1, cte  WHERE t1.from_ = cte.to_ 
    ) 
    SELECT * FROM cte;
    +-------+-------+------+
    | depth | from_ | to_  |
    +-------+-------+------+
    |     0 |     1 |    1 |
    |     1 |     1 |    2 |
    |     1 |     1 |  100 |
    |     2 |     2 |    3 |
    |     3 |     3 |    4 |
    |     4 |     4 |    1 |
    |     5 |     1 |    2 |
    |     5 |     1 |  100 |
    |     6 |     2 |    3 |
    |     7 |     3 |    4 |
    |     8 |     4 |    1 |
    |     9 |     1 |    2 |
    |     9 |     1 |  100 |
    |    10 |     2 |    3 |
    +-------+-------+------+
    WITH RECURSIVE cte (depth, from_, to_) AS ( 
      SELECT 0,1,1 UNION SELECT depth+1, t1.from_, t1.to_ 
        FROM t1, cte WHERE t1.from_ = cte.to_ 
    ) 
    CYCLE from_, to_ RESTRICT 
    SELECT * FROM cte;
    +-------+-------+------+
    | depth | from_ | to_  |
    +-------+-------+------+
    |     0 |     1 |    1 |
    |     1 |     1 |    2 |
    |     1 |     1 |  100 |
    |     2 |     2 |    3 |
    |     3 |     3 |    4 |
    |     4 |     4 |    1 |
    +-------+-------+------+
    scalar_expression comparison_operator ALL <Table subquery>
    <path
    column
    >
    TRUE
    if the comparison operator returns
    TRUE
    for all rows returned by the Table subquery, or if Table subquery returns no rows.
    CREATE TABLE staff (name VARCHAR(10), age TINYINT);
    
    CREATE TABLE customer (name VARCHAR(10), age TINYINT);
    
    INSERT INTO staff VALUES ('Bilhah',37), ('Valerius',61), ('Maia',25);
    
    INSERT INTO customer VALUES ('Thanasis',48), ('Valerius',61), ('Brion',51);
    
    SELECT * FROM staff WHERE (name,age) = (SELECT name,age FROM customer WHERE name='Valerius');
    +----------+------+
    | name     | age  |
    +----------+------+
    | Valerius |   61 |
    +----------+------+
    SELECT name,age FROM staff WHERE (name,age) IN (SELECT name,age FROM customer);
    +----------+------+
    | name     | age  |
    +----------+------+
    | Valerius |   61 |
    +----------+------+
    subquery
    scalar subquery
    CREATE TABLE sq1 (num TINYINT);
    
    CREATE TABLE sq2 (num2 TINYINT);
    
    INSERT INTO sq1 VALUES(100);
    
    INSERT INTO sq2 VALUES(40),(50),(60);
    
    SELECT * FROM sq1 WHERE num > ALL (SELECT * FROM sq2);
    +------+
    | num  |
    +------+
    |  100 |
    +------+
    INSERT INTO sq1 VALUES(30);
    
    SELECT * FROM sq1 WHERE num > ALL (SELECT * FROM sq2);
    +------+
    | num  |
    +------+
    |  100 |
    +------+
    INSERT INTO sq2 VALUES(120);
    
    SELECT * FROM sq1 WHERE num > ALL (SELECT * FROM sq2);
    Empty set (0.00 sec)
    SELECT * FROM sq1 WHERE num > ALL (SELECT * FROM sq2 WHERE num2 > 300);
    +------+
    | num  |
    +------+
    |  100 |
    |   30 |
    +------+
    INSERT INTO sq2 VALUES (NULL);
    
    SELECT * FROM sq1 WHERE num > ALL (SELECT * FROM sq2);
    You can use the keywords ASC and DESC after each ordering expression to force that ordering to be ascending or descending, respectively. Ordering is ascending by default.

    You can also use a single integer as the ordering expression. If you use an integer n, the results is ordered by the nth column in the select expression.

    When string values are compared, they are compared as if by the STRCMP function. STRCMP ignores trailing whitespace and may normalize characters and ignore case, depending on the collation in use.

    Duplicated entries in the ORDER BY clause are removed.

    ORDER BY can also be used to order the activities of a DELETE or UPDATE statement (usually with the LIMIT clause).

    It is possible to use ORDER BY (or LIMIT) in a multi-table UPDATE statement.

    It is not possible to use ORDER BY (or LIMIT) in a multi-table UPDATE statement.

    MariaDB allows packed sort keys and values of non-sorted fields in the sort buffer. This can make filesort temporary files much smaller when VARCHAR, CHAR or BLOB columns are used, notably speeding up some ORDER BY sorts.

    MariaDB does not allow packed sort keys and values of non-sorted fields in the sort buffer.

    Examples

    ORDER BY in an UPDATE statement, in conjunction with LIMIT:

    ORDER BY can be used in a multi-table update:

    See Also

    • SELECT

    • UPDATE

    • DELETE

    This page is licensed: CC BY-SA / Gnu FDL

    SELECT

    EXCEPT

    Return rows from the first result set that do not appear in the second. This set operator performs a subtraction of two datasets.

    EXCEPT

    The result of EXCEPT contains all records of the left SELECT result set except records which are in right SELECT result set. In other words, it is the subtraction of two result sets.

    MINUS is a synonym when is set.

    MINUS is a synonym is not available.

    Syntax

    Brackets for explicit operation precedence are not supported; use a subquery in the FROM clause as a workaround.

    Description

    MariaDB supports EXCEPT and in addition to .

    The queries before and after EXCEPT must be or statements.

    All behavior for naming columns, ORDER BY and LIMIT is the same as for . Note that the alternative syntax is only supported. This allows us to use the WITH TIES clause.

    EXCEPT implicitly supposes a DISTINCT operation.

    The result of EXCEPT is all records of the left SELECT result except records which are in right SELECT result set, i.e. it is subtraction of two result sets.

    EXCEPT and UNION have the same operation precedence and INTERSECT has a higher precedence, unless , in which case all three have the same precedence.

    Parentheses

    Parentheses can be used to specify precedence. Before this, a syntax error would be returned.

    MariaDB starting with

    ALL/DISTINCT

    EXCEPT ALL and EXCEPT DISTINCT . The ALL operator leaves duplicates intact, while the DISTINCT operator removes duplicates. DISTINCT is the default behavior if neither operator is supplied.

    Only EXCEPT DISTINCT is available.

    Examples

    Show customers which are not employees:

    Difference between , EXCEPT and :

    Parentheses for specifying precedence:

    Here is an example that makes use of the storage engine and the statement, to generate a numeric sequence and remove some arbitrary numbers from it:

    See Also

    • (video tutorial)

    This page is licensed: CC BY-SA / Gnu FDL

    SELECT WITH ROLLUP

    Generate super-aggregate summaries. This modifier adds extra rows to the result set representing subtotals and grand totals for grouped columns.

    Syntax

    See SELECT.

    Description

    The WITH ROLLUP modifier adds extra rows to the result set that represent super-aggregate summaries. The super-aggregated column is represented by a NULL value. Multiple aggregates over different columns will be added if there are multiple GROUP BY columns.

    The clause can be used at the same time, and is applied after the WITH ROLLUP rows have been added.

    WITH ROLLUP cannot be used with . Some sorting is still possible by using ASC or DESC clauses with the GROUP BY column, although the super-aggregate rows will always be added last.

    Examples

    These examples use the following sample table

    The WITH ROLLUP modifier in this example adds an extra row that aggregates both years:

    Each time the genre, the year, or the country change, another super-aggregate row is added:

    The LIMIT clause, applied after WITH ROLLUP:

    Sorting by year descending:

    See Also

    This page is licensed: CC BY-SA / Gnu FDL

    Subqueries and ANY

    Compare a value against any result from a subquery. The ANY (or SOME) operator returns TRUE if the comparison holds for at least one row.

    Subqueries using the ANY keyword will return true if the comparison returns true for at least one row returned by the subquery.

    Syntax

    The required syntax for an ANY or SOME quantified comparison is:

    Or:

    • scalar_expression may be any expression that evaluates to a single value.

    • comparison_operator may be any one of =, >, <, >=, <=, <> or !=

    ANY returns:

    • TRUE if the comparison operator returns TRUE for at least one row returned by the Table subquery.

    • FALSE if the comparison operator returns FALSE for all rows returned by the Table subquery, or Table subquery has zero rows.

    • NULL if the comparison operator returns

    SOME is a synonym for ANY, and IN is a synonym for = ANY .

    Examples

    100 is greater than two of the three values, and so the expression evaluates as true.

    SOME is a synonym for ANY:

    IN is a synonym for = ANY, and here there are no matches, so no results are returned:

    Reading this query, the results may be counter-intuitive. It may seem to read as SELECT * FROM sq1 WHERE num does not match any results in sq2. Since it does match 100, it could seem that the results are incorrect. However, the query returns a result if the match does not match any of sq2. Since 100 already does not match 40, the expression evaluates to true immediately, regardless of the 100's matching. It may be more easily readable to use SOME in a case such as this:

    This page is licensed: CC BY-SA / Gnu FDL

    Comma vs JOIN

    Compare implicit and explicit join syntax. This article explains why using the explicit JOIN syntax with an ON clause is preferred over comma-separated tables for readability and precedence.

    A query to retrieve the list of phone numbers for clients who ordered in the last two weeks might be written in a couple of ways. Here are two:

    SELECT *
    FROM
      clients
      INNER JOIN orders ON clients.id = orders.clientId
      INNER JOIN phoneNumbers ON clients.id = phoneNumbers.clientId
    WHERE
      orderPlaced >= NOW() - INTERVAL 2 WEEK;

    Does it make a difference? Not much as written. But you should use the second form, for these reasons:

    • Readability. Once the WHERE clause contains more than two conditions, it becomes tedious to pick out the difference between business logic (only dates in the last two weeks) and relational logic (which fields relate clients to orders). Using the JOIN syntax with an ON clause makes the WHERE list shorter, and makes it very easy to see how tables relate to each other.

    • Flexibility. Let's say we need to see all clients even if they don't have a phone number in the system. With the second version, it's easy; just change INNER JOIN phoneNumbers to LEFT JOIN phoneNumbers. Try that with the first version, and recent MySQL versions will issue a syntax error because of the change in precedence between the comma operator and the JOIN keyword. The solution is to rearrange the FROM clause or add parentheses to override the precedence, and that quickly becomes frustrating.

    • Portability. If your queries use standard SQL syntax, you will have an easier time switching to a different database should the need ever arise.

    See Also

    • — A blog entry about this topic.

    The initial version of this article was copied, with permission, from on 2012-10-05.

    This page is licensed: CC BY-SA / Gnu FDL

    JOIN Syntax

    Review the full syntax for SQL joins in MariaDB. This guide details the structure of table references, index hints, and various join types supported in SELECT, UPDATE, and DELETE statements.

    For an introduction to joins, see .

    Description

    MariaDB supports the following JOIN

    Recursive Common Table Expressions Overview

    Process hierarchical data using recursive CTEs. These expressions reference themselves to repeatedly execute a subquery, perfect for traversing tree structures or generating sequences.

    Common Table Expressions (CTEs) are a standard SQL feature, and are essentially temporary named result sets. CTEs first appeared in the SQL standard in 1999, and the first implementations began appearing in 2007.

    There are two kinds of CTEs:

    • ;

    • Recursive, which this article covers.

    SQL is generally poor at recursive structures.

    Subquery Limitations

    Review restrictions on subquery usage. This page details unsupported operations, such as modifying a table while selecting from it in a subquery.

    There are a number of limitations regarding , which are discussed below.

    The following tables and data will be used in the examples that follow:

    ORDER BY and LIMIT

    To use or limit in both must be used.. For example:

    is valid, but

    is not.

    CREATE TABLE seq (i INT, x VARCHAR(1));
    INSERT INTO seq VALUES (1,'a'), (2,'b'), (3,'b'), (4,'f'), (5,'e');
    
    SELECT * FROM seq ORDER BY i;
    +------+------+
    | i    | x    |
    +------+------+
    |    1 | a    |
    |    2 | b    |
    |    3 | b    |
    |    4 | f    |
    |    5 | e    |
    +------+------+
    
    SELECT * FROM seq ORDER BY i DESC;
    +------+------+
    | i    | x    |
    +------+------+
    |    5 | e    |
    |    4 | f    |
    |    3 | b    |
    |    2 | b    |
    |    1 | a    |
    +------+------+
    
    SELECT * FROM seq ORDER BY x,i;
    +------+------+
    | i    | x    |
    +------+------+
    |    1 | a    |
    |    2 | b    |
    |    3 | b    |
    |    5 | e    |
    |    4 | f    |
    +------+------+
    UPDATE seq SET x='z' WHERE x='b' ORDER BY i DESC LIMIT 1;
    
    SELECT * FROM seq;
    +------+------+
    | i    | x    |
    +------+------+
    |    1 | a    |
    |    2 | b    |
    |    3 | z    |
    |    4 | f    |
    |    5 | e    |
    +------+------+
    CREATE TABLE warehouse (product_id INT, qty INT);
    INSERT INTO warehouse VALUES (1,100),(2,100),(3,100),(4,100);
    
    CREATE TABLE store (product_id INT, qty INT);
    INSERT INTO store VALUES (1,5),(2,5),(3,5),(4,5);
    
    UPDATE warehouse,store SET warehouse.qty = warehouse.qty-2, store.qty = store.qty+2 
      WHERE (warehouse.product_id = store.product_id AND store.product_id  >= 1) 
        ORDER BY store.product_id DESC LIMIT 2;
    
    SELECT * FROM warehouse;
    +------------+------+
    | product_id | qty  |
    +------------+------+
    |          1 |  100 |
    |          2 |  100 |
    |          3 |   98 |
    |          4 |   98 |
    +------------+------+
    
    SELECT * FROM store;
    +------------+------+
    | product_id | qty  |
    +------------+------+
    |          1 |    5 |
    |          2 |    5 |
    |          3 |    7 |
    |          4 |    7 |
    +------------+------+
    scalar_expression comparison_operator ANY <Table subquery>
    SELECT *
    FROM
      clients,
      orders,
      phoneNumbers
    WHERE
      clients.id = orders.clientId
      AND clients.id = phoneNumbers.clientId
      AND orderPlaced >= NOW() - INTERVAL 2 WEEK;

    Joins, Subqueries and SET

    "MySQL joins: ON vs. USING vs. Theta-style"
    Joining Tables with JOIN Clauses Guide
    More Advanced Joins
    JOIN Syntax
    Comma_vs_JOIN
    GROUP BY
  • Common Table Expressions

  • SELECT INTO OUTFILE

  • SELECT INTO DUMPFILE

  • FOR UPDATE

  • LOCK IN SHARE MODE

  • Optimizer Hints

  • LIMIT
    ORDER BY
    SELECT
    Joins and Subqueries
    LIMIT
    ORDER BY
    .
    NULL
    for at least one row returned by the Table subquery and doesn't returns
    TRUE
    for any of them, or if scalar_expression returns
    NULL
    .
    Modifying and Selecting from the Same Table

    It's not possible to both modify and select from the same table in a subquery. For example:

    Row Comparison Operations

    There is only partial support for row comparison operations. The expression in

    must be scalar and the subquery can only return a single column.

    However, because of the way IN is implemented (it is rewritten as a sequence of = comparisons and AND), the expression in

    is permitted to be an n-tuple and the subquery can return rows of n-tuples.

    For example:

    is permitted, but

    is not.

    Correlated Subqueries

    Subqueries in the FROM clause cannot be correlated subqueries. They cannot be evaluated for each row of the outer query since they are evaluated to produce a result set during when the query is executed.

    Stored Functions

    A subquery can refer to a stored function which modifies data. This is an extension to the SQL standard, but can result in indeterminate outcomes. For example, take:

    where f() inserts rows. The function f() could be executed a different number of times depending on how the optimizer chooses to handle the query.

    This sort of construct is therefore not safe to use in replication that is not row-based, as there could be different results on the master and the slave.

    This page is licensed: CC BY-SA / Gnu FDL

    subqueries
    ORDER BY
    LIMIT
    subqueries
    CREATE TABLE booksales ( 
      country VARCHAR(35), genre ENUM('fiction','non-fiction'), year YEAR, sales INT);
    
    INSERT INTO booksales VALUES
      ('Senegal','fiction',2014,12234), ('Senegal','fiction',2015,15647),
      ('Senegal','non-fiction',2014,64980), ('Senegal','non-fiction',2015,78901),
      ('Paraguay','fiction',2014,87970), ('Paraguay','fiction',2015,76940),
      ('Paraguay','non-fiction',2014,8760), ('Paraguay','non-fiction',2015,9030);
    SELECT year, SUM(sales) FROM booksales GROUP BY year;
    +------+------------+
    | year | SUM(sales) |
    +------+------------+
    | 2014 |     173944 |
    | 2015 |     180518 |
    +------+------------+
    2 rows in set (0.08 sec)
    
    SELECT year, SUM(sales) FROM booksales GROUP BY year WITH ROLLUP;
    +------+------------+
    | year | SUM(sales) |
    +------+------------+
    | 2014 |     173944 |
    | 2015 |     180518 |
    | NULL |     354462 |
    +------+------------+
    SELECT country, year, genre, SUM(sales) 
      FROM booksales GROUP BY country, year, genre;
    +----------+------+-------------+------------+
    | country  | year | genre       | SUM(sales) |
    +----------+------+-------------+------------+
    | Paraguay | 2014 | fiction     |      87970 |
    | Paraguay | 2014 | non-fiction |       8760 |
    | Paraguay | 2015 | fiction     |      76940 |
    | Paraguay | 2015 | non-fiction |       9030 |
    | Senegal  | 2014 | fiction     |      12234 |
    | Senegal  | 2014 | non-fiction |      64980 |
    | Senegal  | 2015 | fiction     |      15647 |
    | Senegal  | 2015 | non-fiction |      78901 |
    +----------+------+-------------+------------+
    
    SELECT country, year, genre, SUM(sales) 
      FROM booksales GROUP BY country, year, genre WITH ROLLUP;
    +----------+------+-------------+------------+
    | country  | year | genre       | SUM(sales) |
    +----------+------+-------------+------------+
    | Paraguay | 2014 | fiction     |      87970 |
    | Paraguay | 2014 | non-fiction |       8760 |
    | Paraguay | 2014 | NULL        |      96730 |
    | Paraguay | 2015 | fiction     |      76940 |
    | Paraguay | 2015 | non-fiction |       9030 |
    | Paraguay | 2015 | NULL        |      85970 |
    | Paraguay | NULL | NULL        |     182700 |
    | Senegal  | 2014 | fiction     |      12234 |
    | Senegal  | 2014 | non-fiction |      64980 |
    | Senegal  | 2014 | NULL        |      77214 |
    | Senegal  | 2015 | fiction     |      15647 |
    | Senegal  | 2015 | non-fiction |      78901 |
    | Senegal  | 2015 | NULL        |      94548 |
    | Senegal  | NULL | NULL        |     171762 |
    | NULL     | NULL | NULL        |     354462 |
    +----------+------+-------------+------------+
    SELECT country, year, genre, SUM(sales) 
      FROM booksales GROUP BY country, year, genre WITH ROLLUP LIMIT 4;
    +----------+------+-------------+------------+
    | country  | year | genre       | SUM(sales) |
    +----------+------+-------------+------------+
    | Paraguay | 2014 | fiction     |      87970 |
    | Paraguay | 2014 | non-fiction |       8760 |
    | Paraguay | 2014 | NULL        |      96730 |
    | Paraguay | 2015 | fiction     |      76940 |
    +----------+------+-------------+------------+
    SELECT country, year, genre, SUM(sales) 
      FROM booksales GROUP BY country, year DESC, genre WITH ROLLUP;
    +----------+------+-------------+------------+
    | country  | year | genre       | SUM(sales) |
    +----------+------+-------------+------------+
    | Paraguay | 2015 | fiction     |      76940 |
    | Paraguay | 2015 | non-fiction |       9030 |
    | Paraguay | 2015 | NULL        |      85970 |
    | Paraguay | 2014 | fiction     |      87970 |
    | Paraguay | 2014 | non-fiction |       8760 |
    | Paraguay | 2014 | NULL        |      96730 |
    | Paraguay | NULL | NULL        |     182700 |
    | Senegal  | 2015 | fiction     |      15647 |
    | Senegal  | 2015 | non-fiction |      78901 |
    | Senegal  | 2015 | NULL        |      94548 |
    | Senegal  | 2014 | fiction     |      12234 |
    | Senegal  | 2014 | non-fiction |      64980 |
    | Senegal  | 2014 | NULL        |      77214 |
    | Senegal  | NULL | NULL        |     171762 |
    | NULL     | NULL | NULL        |     354462 |
    +----------+------+-------------+------------+
    scalar_expression comparison_operator SOME <Table subquery>
    CREATE TABLE sq1 (num TINYINT);
    
    CREATE TABLE sq2 (num2 TINYINT);
    
    INSERT INTO sq1 VALUES(100);
    
    INSERT INTO sq2 VALUES(40),(50),(120);
    
    SELECT * FROM sq1 WHERE num > ANY (SELECT * FROM sq2);
    +------+
    | num  |
    +------+
    |  100 |
    +------+
    SELECT * FROM sq1 WHERE num < SOME (SELECT * FROM sq2);
    +------+
    | num  |
    +------+
    |  100 |
    +------+
    SELECT * FROM sq1 WHERE num IN (SELECT * FROM sq2);
    Empty set (0.00 sec)
    INSERT INTO sq2 VALUES(100);
    Query OK, 1 row affected (0.05 sec)
    
    SELECT * FROM sq1 WHERE num <> ANY (SELECT * FROM sq2);
    +------+
    | num  |
    +------+
    |  100 |
    +------+
    SELECT * FROM sq1 WHERE num <> SOME (SELECT * FROM sq2);
    +------+
    | num  |
    +------+
    |  100 |
    +------+
    CREATE TABLE staff(name VARCHAR(10),age TINYINT);
    
    CREATE TABLE customer(name VARCHAR(10),age TINYINT);
    INSERT INTO staff VALUES 
    ('Bilhah',37), ('Valerius',61), ('Maia',25);
    
    INSERT INTO customer VALUES 
    ('Thanasis',48), ('Valerius',61), ('Brion',51);
    SELECT * FROM staff WHERE name IN (SELECT name FROM customer ORDER BY name);
    +----------+------+
    | name     | age  |
    +----------+------+
    | Valerius |   61 |
    +----------+------+
    SELECT * FROM staff WHERE name IN (SELECT NAME FROM customer ORDER BY name LIMIT 1);
    ERROR 1235 (42000): This version of MariaDB doesn't 
      yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
    DELETE FROM staff WHERE name = (SELECT name FROM staff WHERE age=61);
    ERROR 1093 (HY000): Table 'staff' is specified twice, both 
      as a target for 'DELETE' and as a separate source for data
    expr op {ALL|ANY|SOME} subquery,
    expression [NOT] IN subquery
    SELECT * FROM staff WHERE (name,age) NOT IN (
      SELECT name,age FROM customer WHERE age >=51]
    );
    +--------+------+
    | name   | age  |
    +--------+------+
    | Bilhah |   37 |
    | Maia   |   25 |
    +--------+------+
    SELECT * FROM staff WHERE (name,age) = ALL (
      SELECT name,age FROM customer WHERE age >=51
    );
    ERROR 1241 (21000): Operand should contain 1 column(s)
    SELECT ... WHERE x IN (SELECT f() ...);
    syntaxes for the
    table_references
    part of
    statements and multiple-table
    and
    statements:

    A table reference is also known as a join expression.

    Each table can also be specified as db_name.tabl_name. This allows to write queries which involve multiple databases. See Identifier Qualifiers for syntax details.

    The syntax of table_factor is an extension to the SQL Standard. The latter accepts only table_reference, not a list of them inside a pair of parentheses.

    This is a conservative extension if we consider each comma in a list of table_reference items as equivalent to an inner join. Consider this query:

    It is equivalent to this query:

    In MariaDB, CROSS JOIN is a syntactic equivalent toINNER JOIN (they can replace each other). In standard SQL, they are not equivalent. INNER JOIN is used with anON clause, CROSS JOIN is used otherwise.

    In general, parentheses can be ignored in join expressions containing only inner join operations. MariaDB also supports nested joins (see Nested Join Optimization).

    Subqueries

    A table subquery is specified as a parenthesized query and must contain a following derived table name (specified as alias in the above syntax specification).

    You can optionally specify a list of column names in parenthesis.

    Here, the table subquery for t1 will be materialized and named dt2, with column names ic1, ic2, ic3. These column names are used outside the subquery.

    You cannot optionally specify a list of column names in parenthesis.

    See also Correlation Column List.

    System-Versioned Tabled

    See System-versioned tables for more information about the FOR SYSTEM_TIME syntax.

    Index Hints

    Index hints can be specified to affect how the MariaDB optimizer makes use of indexes. For more information, see How to force query plans.

    Oracle Mode

    This feature is available from MariaDB 12.1.

    When is active, the Oracle-style + syntax can be used. For example, the following two queries are identical:

    and

    Similarly, the following two queries are identical:

    and

    Examples

    See Also

    • Joining Tables with JOIN Clauses Guide

    • More Advanced Joins

    • Comma vs JOIN

    • Joins, Subqueries and SET

    This page is licensed: GPLv2, originally from fill_help_tables.sql

    Joining Tables with JOIN Clauses Guide
    SELECT
    DELETE
    UPDATE
    CTEs permit a query to reference itself. A recursive CTE will repeatedly execute subsets of the data until it obtains the complete result set. This makes it particularly useful for handing hierarchical or tree-structured data. max_recursive_iterations avoids infinite loops.

    Syntax example

    WITH RECURSIVE signifies a recursive CTE. It is given a name, followed by a body (the main query) as follows:

    rcte_syntax

    Computation

    Given the following structure:

    rcte_computation

    First execute the anchor part of the query:

    rcte1

    Next, execute the recursive part of the query:

    rcte_computation_2

    Summary

    1. Compute anchor_data.

    2. Compute recursive_part to get the new data.

    3. If (new data is non-empty) goto 2.

    CAST to avoid truncating data

    As currently implemented by MariaDB and by the SQL Standard, data may be truncated if not correctly cast. It is necessary to CAST the column to the correct width if the CTE's recursive part produces wider values for a column than the CTE's nonrecursive part. Some other DBMS give an error in this situation, and MariaDB's behavior may change in future - see MDEV-12325. See the examples below.

    Examples

    Transitive closure - determining bus destinations

    Sample data:

    tc_1

    Now, we want to return the bus destinations with New York as the origin:

    The above example is computed as follows:

    First, the anchor data is calculated:

    • Starting from New York.

    • Boston and Washington are added.

    Next, the recursive part:

    • Starting from Boston and then Washington.

    • Raleigh is added.

    • UNION excludes nodes that are already present.

    Computing paths - determining bus routes

    This time, we are trying to get bus routes such as “New York -> Washington -> Raleigh”.

    Using the same sample data as the previous example:

    CAST to avoid data truncation

    In the following example, data is truncated because the results are not specifically cast to a wide enough type:

    Explicitly use CAST to overcome this:

    This page is licensed: CC BY-SA / Gnu FDL

    Non-recursive
    trees_and_graphs
    INTERSECT
    UNION
    SELECT
    VALUES
    UNION
    SELECT ... OFFSET ... FETCH
    UNION
    INTERSECT
    SEQUENCE
    VALUES
    UNION
    INTERSECT
    Get Set for Set Theory: UNION, INTERSECT and EXCEPT in SQL
    Improvements to ORDER BY Optimization
    Joins and Subqueries
    LIMIT
    GROUP BY
    Common Table Expressions
    SELECT WITH ROLLUP
    SELECT INTO OUTFILE
    SELECT INTO DUMPFILE
    FOR UPDATE
    LOCK IN SHARE MODE
    Optimizer Hints
    SELECT ic1, ic2, ic3 FROM
          (
            SELECT c1, c2, c3 FROM t1 GROUP BY c1
          ) dt2 (ic1, ic2, ic3)
        JOIN t2 ON t2.c1 = dt2.ic1
        WHERE c2 > 0
        GROUP BY ic1
    table_references:
        table_reference [, table_reference] ...
    
    table_reference:
        table_factor
      | join_table
    
    table_factor (<= MariaDB 11.6):
        tbl_name [PARTITION (partition_list)]
            [query_system_time_period_specification] [[AS] alias] [index_hint_list]
      | table_subquery [query_system_time_period_specification] [AS] alias
      | ( table_references )
      | { ON table_reference LEFT OUTER JOIN table_reference
            ON conditional_expr }
    
    table_factor (>= MariaDB 11.7):
        tbl_name [PARTITION (partition_list)]
            [query_system_time_period_specification] [[AS] alias] [index_hint_list]
      | table_subquery [query_system_time_period_specification] [AS] alias [(column_name_list)] 
      | ( table_references )
      | { ON table_reference LEFT OUTER JOIN table_reference
            ON conditional_expr }
    
    join_table:
        table_reference [INNER | CROSS] JOIN table_factor [join_condition]
      | table_reference STRAIGHT_JOIN table_factor
      | table_reference STRAIGHT_JOIN table_factor ON conditional_expr
      | table_reference {LEFT|RIGHT} [OUTER] JOIN table_reference join_condition
      | table_reference NATURAL [{LEFT|RIGHT} [OUTER]] JOIN table_factor
    
    join_condition:
        ON conditional_expr
      | USING (column_list)
    
    query_system_time_period_specification:
        FOR SYSTEM_TIME AS OF point_in_time
      | FOR SYSTEM_TIME BETWEEN point_in_time AND point_in_time
      | FOR SYSTEM_TIME FROM point_in_time TO point_in_time
      | FOR SYSTEM_TIME ALL
    
    point_in_time:
        [TIMESTAMP] expression
      | TRANSACTION expression
    
    index_hint_list:
        index_hint [, index_hint] ...
    
    index_hint:
        USE {INDEX|KEY}
          [{FOR {JOIN|ORDER BY|GROUP BY}] ([index_list])
      | IGNORE {INDEX|KEY}
          [{FOR {JOIN|ORDER BY|GROUP BY}] (index_list)
      | FORCE {INDEX|KEY}
          [{FOR {JOIN|ORDER BY|GROUP BY}] (index_list)
    
    index_list:
        index_name [, index_name] ...
    SELECT * FROM t1 LEFT JOIN (t2, t3, t4)
                     ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)
    SELECT * FROM t1 LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4)
                     ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)
    SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.b;
    SELECT * FROM t1, t2 WHERE t1.a = t2.b(+);
    SELECT * FROM t1 RIGHT JOIN t2 ON t1.a = t2.b;
    SELECT * FROM t1, t2 WHERE t1.a(+) = t2.b;
    SELECT left_tbl.*
      FROM left_tbl LEFT JOIN right_tbl ON left_tbl.id = right_tbl.id
      WHERE right_tbl.id IS NULL;
    WITH RECURSIVE R AS (
      SELECT anchor_data
      UNION [all]
      SELECT recursive_part
      FROM R, ...
    )
    SELECT ...
    CREATE TABLE bus_routes (origin VARCHAR(50), dst VARCHAR(50));
    INSERT INTO bus_routes VALUES 
      ('New York', 'Boston'), 
      ('Boston', 'New York'), 
      ('New York', 'Washington'), 
      ('Washington', 'Boston'), 
      ('Washington', 'Raleigh');
    WITH RECURSIVE bus_dst as ( 
        SELECT origin as dst FROM bus_routes WHERE origin='New York' 
      UNION
        SELECT bus_routes.dst FROM bus_routes JOIN bus_dst ON bus_dst.dst= bus_routes.origin 
    ) 
    SELECT * FROM bus_dst;
    +------------+
    | dst        |
    +------------+
    | New York   |
    | Boston     |
    | Washington |
    | Raleigh    |
    +------------+
    WITH RECURSIVE paths (cur_path, cur_dest) AS (
        SELECT origin, origin FROM bus_routes WHERE origin='New York' 
      UNION
        SELECT CONCAT(paths.cur_path, ',', bus_routes.dst), bus_routes.dst 
         FROM paths
         JOIN bus_routes 
           ON paths.cur_dest = bus_routes.origin AND 
             NOT FIND_IN_SET(bus_routes.dst, paths.cur_path)
    ) 
    SELECT * FROM paths;
    +-----------------------------+------------+
    | cur_path                    | cur_dest   |
    +-----------------------------+------------+
    | New York                    | New York   |
    | New York,Boston             | Boston     |
    | New York,Washington         | Washington |
    | New York,Washington,Boston  | Boston     |
    | New York,Washington,Raleigh | Raleigh    |
    +-----------------------------+------------+
    WITH RECURSIVE tbl AS (
      SELECT NULL AS col
      UNION
      SELECT "THIS NEVER SHOWS UP" AS col FROM tbl
    )
    SELECT col FROM tbl
    +------+
    | col  |
    +------+
    | NULL |
    |      |
    +------+
    WITH RECURSIVE tbl AS (
      SELECT CAST(NULL AS CHAR(50)) AS col
      UNION SELECT "THIS NEVER SHOWS UP" AS col FROM tbl
    )  
    SELECT * FROM tbl;
    +---------------------+
    | col                 |
    +---------------------+
    | NULL                |
    | THIS NEVER SHOWS UP |
    +---------------------+
    SELECT ...
    (INTERSECT [ALL | DISTINCT] | EXCEPT [ALL | DISTINCT] | UNION [ALL | DISTINCT]) 
      SELECT ...
    [(INTERSECT [ALL | DISTINCT] | EXCEPT [ALL | DISTINCT] | UNION [ALL | DISTINCT]) 
      SELECT ...]
    [ORDER BY [{col_name | expr | position} [ASC | DESC] 
      [, {col_name | expr | position} [ASC | DESC] ...]]]
    [LIMIT {[offset,] row_count | row_count OFFSET offset}
    | OFFSET start { ROW | ROWS }
    | FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } { ONLY | WITH TIES } ]
    (SELECT e_name AS name, email FROM customers)
    EXCEPT
    (SELECT c_name AS name, email FROM employees);
    CREATE TABLE seqs (i INT);
    INSERT INTO seqs VALUES (1),(2),(2),(3),(3),(4),(5),(6);
    
    SELECT i FROM seqs WHERE i <= 3 UNION SELECT i FROM seqs WHERE i>=3;
    +------+
    | i    |
    +------+
    |    1 |
    |    2 |
    |    3 |
    |    4 |
    |    5 |
    |    6 |
    +------+
    
    SELECT i FROM seqs WHERE i <= 3 UNION ALL SELECT i FROM seqs WHERE i>=3;
    +------+
    | i    |
    +------+
    |    1 |
    |    2 |
    |    2 |
    |    3 |
    |    3 |
    |    3 |
    |    3 |
    |    4 |
    |    5 |
    |    6 |
    +------+
    
    SELECT i FROM seqs WHERE i <= 3 EXCEPT SELECT i FROM seqs WHERE i>=3;
    +------+
    | i    |
    +------+
    |    1 |
    |    2 |
    +------+
    
    SELECT i FROM seqs WHERE i <= 3 EXCEPT ALL SELECT i FROM seqs WHERE i>=3;
    +------+
    | i    |
    +------+
    |    1 |
    |    2 |
    |    2 |
    +------+
    
    SELECT i FROM seqs WHERE i <= 3 INTERSECT SELECT i FROM seqs WHERE i>=3;
    +------+
    | i    |
    +------+
    |    3 |
    +------+
    
    SELECT i FROM seqs WHERE i <= 3 INTERSECT ALL SELECT i FROM seqs WHERE i>=3;
    +------+
    | i    |
    +------+
    |    3 |
    |    3 |
    +------+
    CREATE OR REPLACE TABLE t1 (a INT);
    CREATE OR REPLACE TABLE t2 (b INT);
    CREATE OR REPLACE TABLE t3 (c INT);
    
    INSERT INTO t1 VALUES (1),(2),(3),(4);
    INSERT INTO t2 VALUES (5),(6);
    INSERT INTO t3 VALUES (1),(6);
    
    ((SELECT a FROM t1) UNION (SELECT b FROM t2)) EXCEPT (SELECT c FROM t3);
    +------+
    | a    |
    +------+
    |    2 |
    |    3 |
    |    4 |
    |    5 |
    +------+
    
    (SELECT a FROM t1) UNION ((SELECT b FROM t2) EXCEPT (SELECT c FROM t3));
    +------+
    | a    |
    +------+
    |    1 |
    |    2 |
    |    3 |
    |    4 |
    |    5 |
    +------+
    (SELECT seq FROM seq_1_to_10) EXCEPT VALUES (2), (3), (4);
    +-----+
    | seq |
    +-----+
    |   1 |
    |   5 |
    |   6 |
    |   7 |
    |   8 |
    |   9 |
    |  10 |
    +-----+

    SELECT

    Retrieve data from the database. This fundamental statement selects columns and rows from tables, supporting filtering, joining, and aggregation.

    Syntax

    [/*+ hints */] syntax is available.

    [/*+ hints */] syntax is not available.

    Available join order hints .

    Join order hints are not available.

    [/*+ MAX_EXECUTION_TIME(milliseconds) */] syntax is available.

    The hint limits the time of statement execution to the number of milliseconds given in the hint argument.

    [/*+ MAX_EXECUTION_TIME(milliseconds) */] syntax is not available.

    Description

    SELECT is used to retrieve rows selected from one or more tables, and can include statements and .

    • Each select_expr expression indicates a column or data that you want to retrieve. You must have at least one select expression. See below.

    • The FROM clause indicates the table or tables from which to retrieve rows. Use either a single table name or a JOIN expression. See for details. If no table is involved, can be specified.

    • Each table can also be specified as db_name

    SELECT can also be used to retrieve rows computed without reference to any table.

    Select Expressions

    A SELECT statement must contain one or more select expressions, separated by commas. Each select expression can be one of the following:

    • The name of a column.

    • Any expression using .

    • * to select all columns from all tables in the FROM clause.

    • tbl_name.*

    When specifying a column, you can either use just the column name or qualify the column name with the name of the table using tbl_name.col_name. The qualified form is useful if you are joining multiple tables in the FROM clause. If you do not qualify the column names when selecting from multiple tables, MariaDB will try to find the column in each table. It is an error if that column name exists in multiple tables.

    You can quote column names using backticks. If you are qualifying column names with table names, quote each part separately as tbl_name`.`col_name.

    If you use any in any of the select expressions, all rows in your results will be implicitly grouped, as if you had used GROUP BY NULL. GROUP BY NULL being an expression behaves specially such that the entire result set is treated as a group.

    DISTINCT

    A query may produce some identical rows. By default, all rows are retrieved, even when their values are the same. To explicitly specify that you want to retrieve identical rows, use the ALL option. If you want duplicates to be removed from the result set, use the DISTINCT option. DISTINCTROW is a synonym for DISTINCT. See also and .

    INTO

    The INTO clause is used to specify that the query results should be written to a file or variable.

    • - formatting and writing the result to an external file.

    • - binary-safe writing of the unformatted results to an external file.

    • - selecting and setting variables.

    The reverse of SELECT INTO OUTFILE is .

    LIMIT

    Restricts the number of returned rows. See and for details.

    LOCK IN SHARE MODE/FOR UPDATE

    See and for details on the respective locking clauses.

    OFFSET ... FETCH

    See .

    The clause doesn't exist.

    ORDER BY

    Order a result set. See for details.

    PARTITION

    Specifies to the optimizer which partitions are relevant for the query. Other partitions will not be read. See for details.

    PROCEDURE

    Passes the whole result set to a C Procedure. See and (the only built-in procedure not requiring the server to be recompiled).

    SKIP LOCKED

    This causes rows that couldn't be locked ( or ) to be excluded from the result set. An explicit NOWAIT is implied here. This is only implemented on tables and ignored otherwise.

    The clause doesn't exist.

    Optimizer Hints

    These include , , , , , and .

    See for details.

    max_statement_time clause

    By using in conjunction with , it is possible to limit the execution time of individual queries. For example:

    WAIT/NOWAIT

    Set the lock wait timeout. See .

    Examples

    See (Beginner tutorial), or the various sub-articles, for more examples.

    See Also

    • (Beginner tutorial)

    This page is licensed: GPLv2, originally from

    UNION

    Combine results from multiple SELECT statements into a single result set. This operator can optionally remove duplicates or include all rows.

    UNION is used to combine the results from multiple statements into a single result set.

    Syntax

    INTERSECT

    Return only rows that appear in both result sets. This set operator identifies the common records shared between two queries.

    Syntax

    Description

    MariaDB has supported INTERSECT

    SELECT
        [/*+ hints */]
        [/*+ JOIN_PREFIX(argument_list) */]
        [/*+ JOIN_ORDER(argument_list) */]
        [/*+ JOIN_FIXED_ORDER(argument_list) */]
        [/*+ JOIN_SUFFIX(argument_list) */]
        [/*+ MAX_EXECUTION_TIME(milliseconds) */]
        [ALL | DISTINCT | DISTINCTROW]
        [HIGH_PRIORITY]
        [STRAIGHT_JOIN]
        [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
        [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
        select_expr [, select_expr ...]
        [ FROM table_references
          [WHERE where_condition]
          [GROUP BY {col_name | expr | position} [ASC | DESC], ... [WITH ROLLUP]]
          [HAVING where_condition]
          [ORDER BY {col_name | expr | position} [ASC | DESC], ...]
          [LIMIT {[offset,] row_count | row_count OFFSET offset  
          [ROWS EXAMINED rows_limit] } |
            [OFFSET start { ROW | ROWS }]
            [FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } { ONLY | WITH TIES }] ]
          procedure|[PROCEDURE procedure_name(argument_list)]
          [INTO OUTFILE 'file_name' [CHARACTER SET charset_name] [export_options] |
            INTO DUMPFILE 'file_name' | INTO var_name [, var_name] ]
          [FOR UPDATE lock_option | LOCK IN SHARE MODE lock_option]
    export_options:
        [{FIELDS | COLUMNS}
            [TERMINATED BY 'string']
            [[OPTIONALLY] ENCLOSED BY 'char']
            [ESCAPED BY 'char']
        ]
        [LINES
            [STARTING BY 'string']
            [TERMINATED BY 'string']
        ]
    lock_option:
        [WAIT n | NOWAIT | SKIP LOCKED]
    .
    tabl_name
    . Each column can also be specified as
    tbl_name
    .
    col_name
    or even
    db_name
    .
    tbl_name
    .
    col_name
    . This allows one to write queries which involve multiple databases. See
    for syntax details.
  • The WHERE clause, if given, indicates the condition or conditions that rows must satisfy to be selected. The where_condition is an expression that evaluates to true for each row to be selected. The statement selects all rows if there is no WHERE clause.

    • In the WHERE clause, you can use any of the functions and operators that MariaDB supports, except for aggregate (summary) functions. See Functions and Operators and Functions and Modifiers for use with GROUP BY (aggregate).

  • Use the ORDER BY clause to order the results.

  • Use the LIMIT clause to restrict the results to only a certain number of rows, optionally with an offset.

  • Use the GROUP BY and HAVING clauses to group rows together when they have columns or computed values in common.

  • to select all columns from just the table
    tbl_name
    .
    GROUP BY
  • Common Table Expressions

  • SELECT WITH ROLLUP

  • SELECT INTO OUTFILE

  • SELECT INTO DUMPFILE

  • FOR UPDATE

  • LOCK IN SHARE MODE

  • Optimizer Hints

  • can be found here
    UNION
    subqueries
    Select Expressions
    JOIN
    FROM DUAL
    functions and operators
    grouping functions
    COUNT DISTINCT
    SELECT INTO OUTFILE
    SELECT INTO DUMPFILE
    SELECT INTO Variable
    LOAD DATA
    LIMIT
    LIMIT ROWS EXAMINED
    LOCK IN SHARE MODE
    FOR UPDATE
    SELECT ... OFFSET ... FETCH
    ORDER BY
    Partition Pruning and Selection
    PROCEDURE
    PROCEDURE ANALYSE
    LOCK IN SHARE MODE
    FOR UPDATE
    InnoDB
    HIGH_PRIORITY
    STRAIGHT_JOIN
    SQL_SMALL_RESULT | SQL_BIG_RESULT
    SQL_BUFFER_RESULT
    SQL_CACHE | SQL_NO_CACHE
    SQL_CALC_FOUND_ROWS
    Optimizer Hints
    max_statement_time
    SET STATEMENT
    WAIT and NOWAIT
    Getting Data from MariaDB
    Getting Data from MariaDB
    Joins and Subqueries
    LIMIT
    ORDER BY
    fill_help_tables.sql
    Identifier Qualifiers
    Description

    UNION is used to combine the results from multiple SELECT statements into a single result set.

    The column names from the first SELECT statement are used as the column names for the results returned. Selected columns listed in corresponding positions of each SELECT statement should have the same data type. (For example, the first column selected by the first statement should have the same type as the first column selected by the other statements.)

    If they don't, the type and length of the columns in the result take into account the values returned by all of the SELECTs, so there is no need for explicit casting. Note that currently this is not the case for recursive CTEs - see MDEV-12325.

    Table names can be specified as db_name.tbl_name. This permits writing UNIONs which involve multiple databases. See Identifier Qualifiers for syntax details.

    UNION queries cannot be used with aggregate functions.

    EXCEPT and UNION have the same operation precedence and INTERSECT has a higher precedence, unless , in which case all three have the same precedence.

    ALL/DISTINCT

    The ALL keyword causes duplicate rows to be preserved. The DISTINCT keyword (the default if the keyword is omitted) causes duplicate rows to be removed by the results.

    UNION ALL and UNION DISTINCT can both be present in a query. In this case, UNION DISTINCT will override any UNION ALL to its left.

    The server can in most cases execute UNION ALL without creating a temporary table (see MDEV-334).

    ORDER BY and LIMIT

    Individual SELECT statements can contain their own ORDER BY and LIMIT clauses. In this case, the individual queries need to be wrapped between parentheses. However, this does not affect the order of the UNION, so they only are useful to limit the record read by one SELECT.

    The UNION can have global ORDER BY and LIMIT clauses, which affect the whole result set. If the columns retrieved by individual SELECT statements have an alias (AS), the ORDER BY must use that alias, not the real column names.

    HIGH_PRIORITY

    Specifying a query as HIGH_PRIORITY does not work inside a UNION. If applied to the first SELECT, it is ignored. Applying to a later SELECT results in a syntax error:

    SELECT ... INTO ...

    Individual SELECT statements cannot be written INTO DUMPFILE or INTO OUTFILE. If the last SELECT statement specifies INTO DUMPFILE or INTO OUTFILE, the entire result of the UNION will be written. Placing the clause after any other SELECT will result in a syntax error.

    If the result is a single row, SELECT ... INTO @var_name can also be used.

    Parentheses

    Parentheses can be used to specify precedence.

    Parentheses cannot be used to specify precedence.

    Examples

    UNION between tables having different column names:

    Specifying the UNION global order and limiting total rows:

    Adding a constant row:

    Differing types:

    Returning the results in order of each individual SELECT by use of a sort column:

    Difference between UNION, EXCEPT and INTERSECT:

    See Also

    • SELECT

    • EXCEPT

    • INTERSECT

    • Recursive Common Table Expressions Overview

    • (video tutorial)

    This page is licensed: GPLv2, originally from fill_help_tables.sql

    SELECT
    (as well as
    ) in addition to
    since
    .

    All behavior for naming columns, ORDER BY and LIMIT is the same as for UNION.

    INTERSECT implicitly supposes a DISTINCT operation.

    The result of an intersect is the intersection of right and left SELECT results, i.e. only records that are present in both result sets will be included in the result of the operation.

    INTERSECT has higher precedence than UNION and EXCEPT (unless running , in which case all three have the same precedence). If possible it will be executed linearly, but if not, it will be translated to a subquery in the FROM clause:

    will be translated to:

    Parentheses

    Parentheses can be used to specify precedence.

    Parentheses cannot be used to specify precedence.

    MariaDB starting with

    ALL/DISTINCT

    INTERSECT ALL and INTERSECT DISTINCT . The ALL operator leaves duplicates intact, while the DISTINCT operator removes duplicates. DISTINCT is the default behavior if neither operator is supplied.

    DISTINCT is the only behavior available.

    Examples

    Show customers which are employees:

    Difference between UNION, EXCEPT and INTERSECT:

    Parentheses for specifying precedence:

    See Also

    • UNION

    • EXCEPT

    • Get Set for Set Theory: UNION, INTERSECT and EXCEPT in SQL (video tutorial)

    This page is licensed: CC BY-SA / Gnu FDL

    EXCEPT
    UNION

    LIMIT

    Restrict the number of rows returned. This clause specifies the maximum number of records to return and can optionally set an offset.

    Description

    Use the LIMIT clause to restrict the number of returned rows. When you use a single integer n with LIMIT, the first n rows will be returned. Use the clause to control which rows come first. You can also select a number of rows after an offset using either of the following:

    When you provide an offset m with a limit n, the first m rows will be ignored, and the following

    SET STATEMENT max_statement_time=100 FOR 
      SELECT field1 FROM table_name ORDER BY field1;
    SELECT f1,f2 FROM t1 WHERE (f3<=10) AND (f4='y');
    SELECT ...
    UNION [ALL | DISTINCT] SELECT ...
    [UNION [ALL | DISTINCT] SELECT ...]
    [ORDER BY [column [, column ...]]]
    [LIMIT {[offset,] row_count | row_count OFFSET offset}]
    ERROR 1234 (42000): Incorrect usage/placement of 'HIGH_PRIORITY'
    (SELECT e_name AS name, email FROM employees)
    UNION
    (SELECT c_name AS name, email FROM customers);
    (SELECT name, email FROM employees)
    UNION
    (SELECT name, email FROM customers)
    ORDER BY name LIMIT 10;
    (SELECT 'John Doe' AS name, 'john.doe@example.net' AS email)
    UNION
    (SELECT name, email FROM customers);
    SELECT CAST('x' AS CHAR(1)) UNION SELECT REPEAT('y',4);
    +----------------------+
    | CAST('x' AS CHAR(1)) |
    +----------------------+
    | x                    |
    | yyyy                 |
    +----------------------+
    (SELECT 1 AS sort_column, e_name AS name, email FROM employees)
    UNION
    (SELECT 2, c_name AS name, email FROM customers) ORDER BY sort_column;
    CREATE TABLE seqs (i INT);
    INSERT INTO seqs VALUES (1),(2),(2),(3),(3),(4),(5),(6);
    
    SELECT i FROM seqs WHERE i <= 3 UNION SELECT i FROM seqs WHERE i>=3;
    +------+
    | i    |
    +------+
    |    1 |
    |    2 |
    |    3 |
    |    4 |
    |    5 |
    |    6 |
    +------+
    
    SELECT i FROM seqs WHERE i <= 3 UNION ALL SELECT i FROM seqs WHERE i>=3;
    +------+
    | i    |
    +------+
    |    1 |
    |    2 |
    |    2 |
    |    3 |
    |    3 |
    |    3 |
    |    3 |
    |    4 |
    |    5 |
    |    6 |
    +------+
    
    SELECT i FROM seqs WHERE i <= 3 EXCEPT SELECT i FROM seqs WHERE i>=3;
    +------+
    | i    |
    +------+
    |    1 |
    |    2 |
    +------+
    
    SELECT i FROM seqs WHERE i <= 3 EXCEPT ALL SELECT i FROM seqs WHERE i>=3;
    +------+
    | i    |
    +------+
    |    1 |
    |    2 |
    |    2 |
    +------+
    
    SELECT i FROM seqs WHERE i <= 3 INTERSECT SELECT i FROM seqs WHERE i>=3;
    +------+
    | i    |
    +------+
    |    3 |
    +------+
    
    SELECT i FROM seqs WHERE i <= 3 INTERSECT ALL SELECT i FROM seqs WHERE i>=3;
    +------+
    | i    |
    +------+
    |    3 |
    |    3 |
    +------+
    CREATE OR REPLACE TABLE t1 (a INT);
    CREATE OR REPLACE TABLE t2 (b INT);
    CREATE OR REPLACE TABLE t3 (c INT);
    
    INSERT INTO t1 VALUES (1),(2),(3),(4);
    INSERT INTO t2 VALUES (5),(6);
    INSERT INTO t3 VALUES (1),(6);
    
    ((SELECT a FROM t1) UNION (SELECT b FROM t2)) INTERSECT (SELECT c FROM t3);
    +------+
    | a    |
    +------+
    |    1 |
    |    6 |
    +------+
    
    (SELECT a FROM t1) UNION ((SELECT b FROM t2) INTERSECT (SELECT c FROM t3));
    +------+
    | a    |
    +------+
    |    1 |
    |    2 |
    |    3 |
    |    4 |
    |    6 |
    +------+
    SELECT ...
    (INTERSECT [ALL | DISTINCT] | EXCEPT [ALL | DISTINCT] | UNION [ALL | DISTINCT]) SELECT ...
    [(INTERSECT [ALL | DISTINCT] | EXCEPT [ALL | DISTINCT] | UNION [ALL | DISTINCT]) SELECT ...]
    [ORDER BY [column [, column ...]]]
    [LIMIT {[offset,] row_count | row_count OFFSET offset}]
    (SELECT a,b FROM t1)
    UNION
    (SELECT c,d FROM t2)
    INTERSECT
    (SELECT e,f FROM t3)
    UNION
    (SELECT 4,4);
    (SELECT a,b FROM t1)
    UNION
    SELECT c,d FROM
      ((SELECT c,d FROM t2)
       INTERSECT
       (SELECT e,f FROM t3)) dummy_subselect
    UNION
    (SELECT 4,4)
    (SELECT e_name AS name, email FROM employees)
    INTERSECT
    (SELECT c_name AS name, email FROM customers);
    CREATE TABLE seqs (i INT);
    INSERT INTO seqs VALUES (1),(2),(2),(3),(3),(4),(5),(6);
    
    SELECT i FROM seqs WHERE i <= 3 UNION SELECT i FROM seqs WHERE i>=3;
    +------+
    | i    |
    +------+
    |    1 |
    |    2 |
    |    3 |
    |    4 |
    |    5 |
    |    6 |
    +------+
    
    SELECT i FROM seqs WHERE i <= 3 UNION ALL SELECT i FROM seqs WHERE i>=3;
    +------+
    | i    |
    +------+
    |    1 |
    |    2 |
    |    2 |
    |    3 |
    |    3 |
    |    3 |
    |    3 |
    |    4 |
    |    5 |
    |    6 |
    +------+
    
    SELECT i FROM seqs WHERE i <= 3 EXCEPT SELECT i FROM seqs WHERE i>=3;
    +------+
    | i    |
    +------+
    |    1 |
    |    2 |
    +------+
    
    SELECT i FROM seqs WHERE i <= 3 EXCEPT ALL SELECT i FROM seqs WHERE i>=3;
    +------+
    | i    |
    +------+
    |    1 |
    |    2 |
    |    2 |
    +------+
    
    SELECT i FROM seqs WHERE i <= 3 INTERSECT SELECT i FROM seqs WHERE i>=3;
    +------+
    | i    |
    +------+
    |    3 |
    +------+
    
    SELECT i FROM seqs WHERE i <= 3 INTERSECT ALL SELECT i FROM seqs WHERE i>=3;
    +------+
    | i    |
    +------+
    |    3 |
    |    3 |
    +------+
    CREATE OR REPLACE TABLE t1 (a INT);
    CREATE OR REPLACE TABLE t2 (b INT);
    CREATE OR REPLACE TABLE t3 (c INT);
    
    INSERT INTO t1 VALUES (1),(2),(3),(4);
    INSERT INTO t2 VALUES (5),(6);
    INSERT INTO t3 VALUES (1),(6);
    
    ((SELECT a FROM t1) UNION (SELECT b FROM t2)) INTERSECT (SELECT c FROM t3);
    +------+
    | a    |
    +------+
    |    1 |
    |    6 |
    +------+
    
    (SELECT a FROM t1) UNION ((SELECT b FROM t2) INTERSECT (SELECT c FROM t3));
    +------+
    | a    |
    +------+
    |    1 |
    |    2 |
    |    3 |
    |    4 |
    |    6 |
    +------+
    n
    rows will be returned.

    Executing an UPDATE with the LIMIT clause is not safe for replication. LIMIT 0 is an exception to this rule (see MDEV-6170).

    There is a LIMIT ROWS EXAMINED optimization which provides the means to terminate the execution of SELECT statements which examine too many rows, and thus use too many resources. See LIMIT ROWS EXAMINED.

    Multi-Table Updates

    It is possible to use LIMIT (or ORDER BY) in a multi-table UPDATE statement.

    It is not possible to use LIMIT (or ORDER BY) in a multi-table UPDATE statement.

    GROUP_CONCAT

    It is possible to use LIMIT with GROUP_CONCAT().

    It is not possible to use LIMIT with GROUP_CONCAT().

    Examples

    Select the first two names (no ordering specified):

    All the names in alphabetical order:

    The first two names, ordered alphabetically:

    The third name, ordered alphabetically (the first name would be offset zero, so the third is offset two):

    From , LIMIT can be used in a multi-table update:

    When using LIMIT with GROUP_CONCAT, you can simplify certain queries. Consider this table:

    The following query works fine, but is rather complex:

    It can be simplified to this:

    See Also

    • OFFSET ... FETCH Like limit, but also support WITH TIES

    • ROWNUM() function

    • SELECT

    • UPDATE

    This page is licensed: CC BY-SA / Gnu FDL

    ORDER BY
    Get Set for Set Theory: UNION, INTERSECT and EXCEPT in SQL
    LIMIT offset, row_count
    LIMIT row_count OFFSET offset
    CREATE TABLE members (name VARCHAR(20));
    INSERT INTO members VALUES('Jagdish'),('Kenny'),('Rokurou'),('Immaculada');
    
    SELECT * FROM members;
    +------------+
    | name       |
    +------------+
    | Jagdish    |
    | Kenny      |
    | Rokurou    |
    | Immaculada |
    +------------+
    SELECT * FROM members LIMIT 2;
    +---------+
    | name    |
    +---------+
    | Jagdish |
    | Kenny   |
    +---------+
    SELECT * FROM members ORDER BY name;
    +------------+
    | name       |
    +------------+
    | Immaculada |
    | Jagdish    |
    | Kenny      |
    | Rokurou    |
    +------------+
    SELECT * FROM members ORDER BY name LIMIT 2;
    +------------+
    | name       |
    +------------+
    | Immaculada |
    | Jagdish    |
    +------------+
    SELECT * FROM members ORDER BY name LIMIT 2,1;
    +-------+
    | name  |
    +-------+
    | Kenny |
    +-------+
    CREATE TABLE warehouse (product_id INT, qty INT);
    INSERT INTO warehouse VALUES (1,100),(2,100),(3,100),(4,100);
    
    CREATE TABLE store (product_id INT, qty INT);
    INSERT INTO store VALUES (1,5),(2,5),(3,5),(4,5);
    
    UPDATE warehouse,store SET warehouse.qty = warehouse.qty-2, store.qty = store.qty+2 
      WHERE (warehouse.product_id = store.product_id AND store.product_id  >= 1) 
        ORDER BY store.product_id DESC LIMIT 2;
    
    SELECT * FROM warehouse;
    +------------+------+
    | product_id | qty  |
    +------------+------+
    |          1 |  100 |
    |          2 |  100 |
    |          3 |   98 |
    |          4 |   98 |
    +------------+------+
    
    SELECT * FROM store;
    +------------+------+
    | product_id | qty  |
    +------------+------+
    |          1 |    5 |
    |          2 |    5 |
    |          3 |    7 |
    |          4 |    7 |
    +------------+------+
    CREATE TABLE d (dd DATE, cc INT);
    
    INSERT INTO d VALUES ('2017-01-01',1);
    INSERT INTO d VALUES ('2017-01-02',2);
    INSERT INTO d VALUES ('2017-01-04',3);
    SELECT SUBSTRING_INDEX(GROUP_CONCAT(CONCAT_WS(":",dd,cc) 
    ORDER BY cc DESC),",",1) FROM d;
    +----------------------------------------------------------------------------+
    | SUBSTRING_INDEX(GROUP_CONCAT(CONCAT_WS(":",dd,cc) ORDER BY cc DESC),",",1) |
    +----------------------------------------------------------------------------+
    | 2017-01-04:3                                                               |
    +----------------------------------------------------------------------------+
    SELECT GROUP_CONCAT(CONCAT_WS(":",dd,cc) 
    ORDER BY cc DESC LIMIT 1) FROM d;
    +-------------------------------------------------------------+
    | GROUP_CONCAT(CONCAT_WS(":",dd,cc) ORDER BY cc DESC LIMIT 1) |
    +-------------------------------------------------------------+
    | 2017-01-04:3                                                |
    +-------------------------------------------------------------+
    DELETE
    Joins and Subqueries
    ORDER BY
    GROUP BY
    Common Table Expressions
    SELECT WITH ROLLUP
    SELECT INTO OUTFILE
    SELECT INTO DUMPFILE
    FOR UPDATE
    LOCK IN SHARE MODE
    Optimizer Hints
    SELECT ... OFFSET ... FETCH

    Subqueries and JOINs

    Understand when to use subqueries versus joins. This guide explains performance implications and how to rewrite subqueries as joins for efficiency.

    A subquery can quite often, but not in all cases, be rewritten as a JOIN.

    Rewriting Subqueries as JOINS

    A subquery using IN can be rewritten with the DISTINCT keyword. Consider this query:

    It can be rewritten like this:

    NOT IN or NOT EXISTS queries can also be rewritten. For example, these two queries return the same result:

    They can both be rewritten like this:

    Subqueries that can be rewritten as a LEFT JOIN are sometimes more efficient.

    Using Subqueries instead of JOINS

    There are some scenarios, though, which call for subqueries rather than joins:

    • When you want duplicates, but not false duplicates. Suppose Table_1 has three rows — {1,1,2} — and Table_2 has two rows — {1,2,2}. If you need to list the rows in Table_1 which are also in Table_2, only this subquery-based SELECT

    • This SQL statement won't work:

    • because the result will be {1,1,2,2} — and the duplication of 2 is an error. This SQL statement won't work either:

    • because the result will be {1,2} — and the removal of the duplicated 1 is an error too.

    • When the outermost statement is not a query. The SQL statement:

    • can't be expressed using a join unless some rare SQL3 features are used.

    • When the join is over an expression. The SQL statement:

    • is hard to express with a join. In fact, the only way we can think of is this SQL statement:

    • which still involves a parenthesized query, so nothing is gained from the transformation.

    • When you want to see the exception. For example, suppose the question is: Which books are longer than Das Kapital? These two queries are effectively almost the same:

    • The difference is between these two SQL statements is, if there are two editions of Das Kapital (with different page counts), then the self-join example will return the books which are longer than the shortest edition of Das Kapital. That might be the wrong answer, since the original question didn't ask for "... longer than ANY book named Das Kapital" (it seems to contain a false assumption that there's only one edition).

    This page is licensed: CC BY-SA / Gnu FDL

    SELECT * FROM table1 WHERE col1 IN (SELECT col1 FROM table2);
    SELECT DISTINCT table1.* FROM table1, table2 WHERE table1.col1=table2.col1;
    statement will give the right answer (
    1
    ,
    1
    ,
    2
    ):
    SELECT * FROM table1 WHERE col1 NOT IN (SELECT col1 FROM table2);
    SELECT * FROM table1 WHERE NOT EXISTS (SELECT col1 FROM table2 
             WHERE table1.col1=table2.col1);
    SELECT table1.* FROM table1 LEFT JOIN table2 ON table1.id=table2.id 
           WHERE table2.id IS NULL;
    SELECT Table_1.column_1 
    FROM   Table_1 
    WHERE  Table_1.column_1 IN 
      (SELECT Table_2.column_1 
        FROM   Table_2);
    SELECT Table_1.column_1 
    FROM   Table_1,Table_2 
    WHERE  Table_1.column_1 = Table_2.column_1;
    SELECT DISTINCT Table_1.column_1 
    FROM   Table_1,Table_2 
    WHERE  Table_1.column_1 = Table_2.column_1;
    UPDATE Table_1 SET column_1 = (SELECT column_1 FROM Table_2);
    SELECT * FROM Table_1 
    WHERE column_1 + 5 =
      (SELECT MAX(column_1) FROM Table_2);
    SELECT Table_1.*
    FROM   Table_1, 
          (SELECT MAX(column_1) AS max_column_1 FROM Table_2) AS Table_2
    WHERE  Table_1.column_1 + 5 = Table_2.max_column_1;
    SELECT DISTINCT Bookcolumn_1.*                     
    FROM   Books AS Bookcolumn_1 JOIN Books AS Bookcolumn_2 USING(page_count) 
    WHERE  title = 'Das Kapital';
    
    SELECT DISTINCT Bookcolumn_1.* 
    FROM   Books AS Bookcolumn_1 
    WHERE  Bookcolumn_1.page_count > 
      (SELECT DISTINCT page_count 
      FROM   Books AS Bookcolumn_2 
      WHERE  title = 'Das Kapital');
    Why is ORDER BY in a FROM subquery ignored?
    10.6.0
    Anonymous subqueries in a FROM clause
    ORACLE mode
    ORACLE mode
    11.7.0
    SQL_MODE=ORACLE
    SQL_MODE=ORACLE
    running in Oracle mode
    10.5.0
    Oracle mode
    SELECT UNIQUE in Oracle mode
    Oracle mode from MariaDB 10.3
    running in Oracle mode
    MariaDB 10.3
    running in Oracle mode
    10.5.0
    MariaDB 10.3.2