jet/wiki/SELECT.md
2019-06-29 16:58:41 +02:00

5.8 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

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
9. FOR clause
Go:
.FOR(jet.NO_KEY_UPDATE)

SQL:
FOR NO KEY UPDATE

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:

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)