7.5 KiB
SELECT statement is used to retrieve records from one or more tables in PostgreSQL. More about SELECT statement in postgres can be found at: https://www.postgresql.org/docs/11/sql-select.html
Following clauses are supported:
-
SELECT(expressions...) - expressions to form output rows of the SELECT statement.
-
DISTINCT() - remove all duplicate rows from result set
-
FROM(tableSource...) - specifies one or more source tables for the SELECT.
-
WHERE(condition) - only rows for which condition returns true will be selected.
-
GROUP BY(groupingElement, ...) - will condense into a single row all selected rows that share the same values for the grouped expressions.
-
HAVING(condition) - eliminates group rows that do not satisfy the condition
-
ORDER BY(orderBy, ...) - causes the result rows to be sorted according to the specified expression(s)
-
LIMIT(count) - specifies the maximum number of rows to return
-
OFFSET(start) - specifies the number of rows to skip before starting to return rows
-
FOR(lockMode) - how SELECT will lock rows as they are obtained from the table
Lock mode can be:- jet.UPDATE()
- jet.NO_KEY_UPDATE()
- jet.SHARE()
- jet.KEY_SHARE()
Lock mode can be extended with following clauses:
- NOWAIT()
- SKIP_LOCKED()
-
UNION(select) / UNION_ALL(select) - computes the set union of the rows returned by the involved SELECT statements
-
INTERSECT(select) / INTERSECT_ALL(select) - computes the set intersection of the rows returned by the involved SELECT statements
-
EXCEPT(select) / EXCEPT_ALL(select) - computes the set of rows that are in the result of the left SELECT statement but not in the result of the right one
This list might be extended with feature Jet releases.
Examples per clause
1. SELECT clause
Sample SELECT clause written in Go:
jet.SELECT(
jet.Int(1).ADD(jet.Int(12)).SUB(jet.Int(21)), // arbitrary expression
table.Film.Name, // column
table.Customer.FirstName.CONCAT(table.Customer.LastName).AS("FullName") // alias
)
If jet and autogenerated table package, is dot "." imported, above statement will look more like native SQL:
SELECT(
Int(1).ADD(Int(12)).SUB(Int(21)), // arbitrary expression
Film.Name, // column
Customer.FirstName.CONCAT(Customer.LastName).AS("FullName") // alias
)
For the most of the wiki dot import is used.
Above SQL clause written in go will produce following raw SQL:
SELECT 1 + 12 - 21,
film.name AS "film.name", --
customer.first_name || customer.last_name AS "FullName"
film.name AS "film.name" - column names are aliased by default. Alias is used during execution to map row result to
appropriate model structure.
2. DISTINCT clause
SELECT(Film.Name).
.DISTINCT().
Raw SQL:
SELECT DISTINCT film.name
3. FROM clause
Go:
1).FROM(Film)
2).FROM(
Film.
INNER_JOIN(Language, Langauge.LanguageID.EQ(Film.FilmID))
)
SQL:
1)FROM dvds.film
2)FROM Film
INNER JOIN Language ON (Language.LanguageID = Film.FilmID)
4. WHERE clause
Go:
.WHERE(Film.Length.GT(Int(150)))
SQL:
WHERE film.length > 150
5. GROUP BY clause
Go:
.GROUP_BY(Film.Length)
SQL:
GROUP BY film.length
6. HAVING clause
Go:
.HAVING(Film.Length.GT(Int(150))
SQL:
HAVING film.length > 150
7. ORDER BY clause
Go:
.ORDER_BY(Film.Length)
SQL:
ORDER BY film.length
8. LIMIT clause
Go:
.LIMIT(11)
SQL:
LIMIT 11
9. OFFSET clause
Go:
.OFFSET(11)
SQL:
OFFSET 11
9. FOR clause
Go:
.FOR(jet.NO_KEY_UPDATE().SKIP_LOCKED())
SQL:
FOR NO KEY UPDATE SKIP LOCKED
10. Set clauses (UNION, UNION_ALL, INTERSECT, INTERSECT_ALL, EXCEPT, EXCEPT_ALL)
Go:
SELECT(Payment.Amount).FROM(Payment)
UNION_ALL(SELECT(Payment.Amount).FROM(Payment))
Sql:
(
(
SELECT payment.amount AS "payment.amount"
FROM dvds.payment
)
UNION
(
SELECT payment.amount AS "payment.amount"
FROM dvds.payment
)
);
Two forms of select statements in Jet
1. Classical select statement
Columns selected are before table source selected
SELECT(
Payment.AllColumns,
Customer.AllColumns,
).
FROM(Payment.
INNER_JOIN(Customer, Payment.CustomerID.EQ(Customer.CustomerID))).
ORDER_BY(Payment.PaymentID.ASC()).
LIMIT(30)
2. Jet select statement
Table sources are before columns selected. There is no FROM.
Payment.
INNER_JOIN(Customer, Payment.CustomerID.EQ(Customer.CustomerID))
SELECT(
Payment.AllColumns,
Customer.AllColumns,
).
ORDER_BY(Payment.PaymentID.ASC()).
LIMIT(30)
Second form is added, because sometimes feels more natural to first think about the tables
of interest, and than about the columns.
Both forms produces exactly the same raw SQL.
Sub-queries
How to write SELECT statement with sub-queries?
Sub-queries are composed first:
// select film_id and title from film table that have 'R' rating.
rRatingFilms := Film.
SELECT(
Film.FilmID,
Film.Title,
).
WHERE(Film.Rating.EQ(enum.MpaaRating.R)).
AsTable("rFilms")
AsTable("rFilms") - allows SELECT statements to be seen as table.
To use sub-query columns in SELECT statement expressions we have to export column from sub-query,
using From method.
rFilmId := Film.FilmID.From(rRatingFilms) //used for join condition
Now we can write:
query := Actor.
INNER_JOIN(FilmActor, Actor.ActorID.EQ(FilmActor.FilmID)).
INNER_JOIN(rRatingFilms, FilmActor.FilmID.EQ(rFilmId)).
SELECT(
Actor.AllColumns,
FilmActor.AllColumns,
rRatingFilms.AllColumns(),
)
rRatingFilms.AllColumns(), - sub-query columns needed for projection can be exported with AllColumns() method.
No need to export each one of them with From.
Debug SQL of above example:
SELECT actor.actor_id AS "actor.actor_id",
actor.first_name AS "actor.first_name",
actor.last_name AS "actor.last_name",
actor.last_update AS "actor.last_update",
film_actor.actor_id AS "film_actor.actor_id",
film_actor.film_id AS "film_actor.film_id",
film_actor.last_update AS "film_actor.last_update",
"rFilms"."film.film_id" AS "film.film_id",
"rFilms"."film.title" AS "film.title",
"rFilms"."film.rating" AS "film.rating"
FROM dvds.actor
INNER JOIN dvds.film_actor ON (actor.actor_id = film_actor.film_id)
INNER JOIN (
SELECT film.film_id AS "film.film_id",
film.title AS "film.title",
film.rating AS "film.rating"
FROM dvds.film
WHERE film.rating = 'R'
) AS "rFilms" ON (film_actor.film_id = "rFilms"."film.film_id");
What If sub-query projection is not a column?
For instance:
customersPayments := Payment.
SELECT(
Payment.CustomerID,
SUMf(Payment.Amount).AS("amount_sum"),
).
GROUP_BY(Payment.CustomerID).
AsTable("customer_payment_sum")
customerId := Payment.CustomerID.From(customersPayments)
To export "amount_sum" from customersPayments sub-query we have to create column first with appropriate type and a name.
Because SUMf produces float expression we will create FloatColumn with name of the column alias "amount_sum"
amountSum := FloatColumn("amount_sum").From(customersPayments)