2019-06-29 16:58:41 +02:00
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## SELECT statement clauses
|
|
|
|
|
|
|
|
|
|
Following clauses are supported - SELECT, DISTINCT, FROM, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT, OFFSET and FOR.
|
|
|
|
|
_This list might be extended with feature Jet releases._
|
|
|
|
|
|
|
|
|
|
##### 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
|
|
|
|
|
```
|
|
|
|
|
|
2019-07-01 13:18:39 +02:00
|
|
|
##### 9. FOR clause
|
|
|
|
|
|
|
|
|
|
Lock mode can be:
|
|
|
|
|
- jet.UPDATE()
|
|
|
|
|
- jet.NO_KEY_UPDATE()
|
|
|
|
|
- jet.SHARE()
|
|
|
|
|
- jet.KEY_SHARE()
|
|
|
|
|
|
|
|
|
|
Lock mode has following clauses:
|
|
|
|
|
- NOWAIT()
|
|
|
|
|
- SKIP_LOCKED()
|
|
|
|
|
|
2019-06-29 16:58:41 +02:00
|
|
|
```
|
|
|
|
|
Go:
|
2019-07-01 13:18:39 +02:00
|
|
|
.FOR(jet.NO_KEY_UPDATE().SKIP_LOCKED())
|
2019-06-29 16:58:41 +02:00
|
|
|
|
|
|
|
|
SQL:
|
2019-07-01 13:18:39 +02:00
|
|
|
FOR NO KEY UPDATE SKIP LOCKED
|
2019-06-29 16:58:41 +02:00
|
|
|
```
|
|
|
|
|
|
2019-07-01 13:18:39 +02:00
|
|
|
|
2019-06-29 16:58:41 +02:00
|
|
|
### Two forms of select statements in Jet
|
|
|
|
|
|
|
|
|
|
#### 1. Classical select statement
|
|
|
|
|
Columns selected are before tables 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
|
|
|
|
|
Joined tables(or just one) 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:
|
|
|
|
|
```sql
|
|
|
|
|
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)
|
|
|
|
|
```
|