# Querying
### Selecting all columns
All columns from all joined tables can be queried with `SELECT *` statement.
```sql
SELECT *
FROM products;
```
### Selecting specific columns
```sql
SELECT id, customer_name, ip
FROM customers;
```
### Filtering entries
```sql
SELECT id, customer_name, email
FROM customers
WHERE country = 'SE' AND city = 'Arvika';
```
### Ordering by column value
```sql
SELECT id, customer_name
FROM customers
ORDER BY customer_name ASC;
```
Currently only one column can be used in the `ORDER BY` clause.
The order may be either ascending (`ASC` suffix, default) or descending (`DESC` suffix).
Ordering rows by a value of a column requires a matching index on that column.
### INNER JOIN
immudb supports standard SQL `INNER JOIN` syntax.
The `INNER` join type is optional.
```sql
SELECT *
FROM orders
INNER JOIN customers ON orders.customerid = customers.id;
SELECT *
FROM orders
JOIN customers ON orders.customerid = customers.id
WHERE orders.productid = 2;
SELECT * FROM orders
JOIN customers ON customers.id = orders.customerid
JOIN products ON products.id = orders.productid;
```
### LIKE operator
immudb supports the `LIKE` operator.
Unlike in other SQL engines though, the pattern use a regexp syntax
supported by the [regexp library in the go language](https://pkg.go.dev/regexp).
A `NOT` prefix negates the value of the `LIKE` operator.
```sql
SELECT product
FROM products
WHERE product LIKE '(J.*ce|Red)';
SELECT product
FROM products
WHERE product NOT LIKE '(J.*ce|Red)';
SELECT id, product
FROM products
WHERE (id > 0 AND NOT products.id >= 10)
AND (products.product LIKE 'J');
```
### IN operator
immudb has a basic supports for the `IN` operator.
A `NOT` prefix negates the value of the `IN` operator.
Note: Currently the list for the `IN` operator can not be
calculated using a sub-query.
```sql
SELECT product
FROM products
WHERE product IN ('Milk', 'Grapes - Red');
SELECT product
FROM products
WHERE product NOT IN ('Milk', 'Grapes - Red');
SELECT id, product
FROM products
WHERE (id > 0 AND NOT products.id >= 10)
AND (product IN ('Milk', 'Grapes - Red'));
```
### Column and table aliasing
```sql
SELECT c.id, c.customer_name AS name, active
FROM customers AS c
WHERE c.id <= 3 AND c.active = true;
SELECT c.id, c.customer_name AS name, active
FROM customers c
WHERE c.id <= 3 AND c.active = true;
```
Table name aliasing is necessary when using more than one join with the same table.
### Aggregations
Available aggregation functions:
* COUNT
* SUM
* MAX
* MIN
* AVG
```sql
SELECT
COUNT(*) AS c,
SUM(age),
MIN(age),
MAX(age),
AVG(age)
FROM customers;
```
### Grouping results with GROUP BY
Results can be grouped by a value of a single column.
That column must also be used in a matching `ORDER BY` clause.
```sql
SELECT COUNT(*) as customer_count, country
FROM customers
GROUP BY country
ORDER BY country;
```
### Filtering grouped results with HAVING
```sql
SELECT
active,
COUNT(*) as c,
MIN(age),
MAX(age)
FROM customers
GROUP BY active
HAVING COUNT(*) > 0
ORDER BY active DESC;
```
### Sub-queries
The table in the `SELECT` or `JOIN` clauses can be replaced with a sub-query.
```sql
SELECT * FROM (
SELECT id, customer_name
FROM customers
WHERE age < 30
)
INNER JOIN customer_review
ON customer_review.customerid = customers.id;
SELECT * FROM (
SELECT id, customer_name
FROM customers
WHERE age < 30
) AS c
INNER JOIN (
SELECT * FROM customer_review
) AS r
ON r.customerid = c.id;
```
Note: the context of a sub-query does not propagate outside,
e.g. it is not possible to reference a table from a sub-query
in the `WHERE` clause outside of the sub-query.
### Combining query results with UNION
It is possible to combine multiple query results with the `UNION` operator.
Subqueries must select the same number and type of columns.
The final return will assign the same naming as in the first subquery, even if names differ.
```sql
SELECT customer_name as name
FROM customers
WHERE age < 30
UNION
SELECT seller_name
FROM sellers
WHERE age < 30
```
Subqueries are not constrained in any way, they can contain aggregations or joins.
Duplicate rows are excluded by default. Using `UNION ALL` will leave duplicate rows in place.
```sql
SELECT AVG(age) FROM customers
UNION ALL
SELECT AVG(age) FROM sellers
```
### Transactions
The ACID (Atomicity, Consistency, Isolation, and Durability) compliance is complete.
Handling read-write conflicts may be necessary when dealing with concurrent transactions. Getting the error `ErrTxReadConflict` ("tx read conflict") means there was another transaction committed before the current one, and the data it read may have been invalidated.
[MVCC](https://en.wikipedia.org/wiki/Multiversion_concurrency_control) validations have not yet been implemented, therefore there may be false positives generated. In case of conflict, a new attempt may be required.
```sql
BEGIN TRANSACTION;
UPSERT INTO products (id, price, product)
VALUES (4, '$5.76', 'Bread');
INSERT INTO orders(productid, customerid)
VALUES(4, 1);
COMMIT;
```
### Time travel
Time travel allows you to read data from SQL as if it were in a previous state or from a specific time range.
Initial and final points are optional and can be specified using either a transaction ID or a timestamp.
The temporal range can be used to filter out rows from the specified (physical) table, but it is not supported in subqueries.
The initial point can be inclusive (`SINCE`) or exclusive (`AFTER`).
The final point can be inclusive (`UNTIL`) or exclusive (`BEFORE`).
```sql
SELECT id, product, price
FROM products BEFORE TX 13
WHERE id = 2;
```
```sql
SELECT * FROM sales SINCE '2022-01-06 11:38' UNTIL '2022-01-06 12:00'
```
Temporal ranges can be specified using functions and parameters
```sql
SELECT * FROM mytable SINCE TX @initialTx BEFORE now()
```