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 Lock mode can be: - jet.UPDATE() - jet.NO_KEY_UPDATE() - jet.SHARE() - jet.KEY_SHARE() Lock mode has following clauses: - NOWAIT() - SKIP_LOCKED() ``` Go: .FOR(jet.NO_KEY_UPDATE().SKIP_LOCKED()) SQL: FOR NO KEY UPDATE SKIP LOCKED ``` ### 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) ```