-
-
Notifications
You must be signed in to change notification settings - Fork 2
SELECT
The SELECT
statement.
See APIS ➞
client.query()
,table.select()
Section | Description |
---|---|
Basic Select | Run a basic SELECT query. |
The WHERE Clause |
Specify conditions against which to filter records. |
The ORDER BY Clause |
Sort output rows by specific criteria. |
The LIMIT Clause |
Restrict the number of rows returned by a query. |
The OFFSET Clause |
Skip a specified number of rows before returning rows. |
The JOIN Clause |
Select records from one table and tie in relevamt records from related tables. |
The GROUP BY Clause |
Group rows together by specific criteria for use with aggregate functions. |
The HAVING Clause |
Filter groups based on the result of aggregate functions. |
The WINDOW Clause |
Define reusable window specifications for window functions. |
Structuring Syntax | Structure your output data without all the rough work. |
Magic Paths | Express relationships graphically. |
Select all fields from all records:
// (a): SQL syntax
const result = await client.query(
`SELECT *
FROM public.users`
);
// (b): Function-based syntax
const result = await client.database('public').table('users').select();
Use the WHERE
clause to specify conditions against which to filter records.
Find records that satisfy two specific conditions:
// (a): SQL syntax
const result = await client.query(
`SELECT *
FROM public.users
WHERE name = 'John' AND role = 'guest'`
);
// (b): Object-based syntax
const result = await client.database('public').table('users').select(
{ where: [
{ eq: ['name', { value: 'John' }] },
{ eq: ['role', { value: 'guest' }] }
] }
);
// (c): Function-based syntax
const result = await client.database('public').table('users').select(
{ where: [
(q) => q.eq('name', (r) => r.value('John')),
(q) => q.eq('role', (r) => r.value('guest'))
] }
);
Find records that satisfy a combination of static and dynamic conditions:
// (a): SQL syntax
const result = await client.query(
`SELECT
name,
email
FROM public.users
WHERE role IS NOT NULL AND COALESCE(email, phone) IS NOT NULL`
);
// (b): Object-based syntax
const result = await client.database('public').table('users').select({
fields: [ 'name', 'email' ],
where: [
{ isNotNull: 'role' },
{ isNotNull: { fn: ['COALESCE', 'email', 'phone'] } }
]
});
// (c): Function-based syntax
const result = await client.database('public').table('users').select({
fields: [ 'name', 'email' ],
where: [
{ isNotNull: 'role' },
{ isNotNull: { fn: ['COALESCE', 'email', 'phone'] } }
]
});
Find records that satisfy a more complex set of conditions:
// (a): SQL syntax
const result = await client.query(
`SELECT
name,
email
FROM public.users
WHERE (role = $1 OR role = $2) AND (
email IS NOT NULL OR (
phone IS NOT NULL AND country_code IS NOT NULL
)
)`
);
// (b): Object-based syntax
const result = await client.database('public').table('users').select({
fields: [ 'name', 'email' ],
where: [
{ some: [
{ eq: ['role', { binding: 'admin' }] },
{ eq: ['role', { binding: 'contributor' }] }
] },
{ some: [
{ isNotNull: 'email' },
{ every: [
{ isNotNull: 'phone' },
{ isNotNull: 'country_code' }
] }
] }
]
});
// (c): Function-based syntax
const result = await client.database('public').table('users').select({
fields: [ 'name', 'email' ],
where: [
(q) => q.some(
(r) => r.eq('role', (s) => s.binding('admin')),
(r) => r.eq('role', (s) => s.binding('contributor')),
),
(q) => q.some(
(r) => r.isNotNull('email'),
(r) => r.every(
(s) => s.isNotNull('phone'),
(s) => s.isNotNull('country_code')
)
)
]
});
Use the ORDER BY
clause to sort output rows by specific criteria.
Order output rows by a set of dynamic and static criteria:
// (a): SQL syntax
const result = await client.query(
`SELECT
name,
email
FROM public.users
ORDER BY
CASE role WHEN 'admin' THEN 1 WHEN 'contributor' THEN 2 ELSE 3 END ASC,
CASE WHEN phone IS NULL THEN 0 ELSE 1 END DESC,
name ASC`
);
// (b): Object-based syntax
const result = await client.database('public').table('users').select({
fields: [ 'name', 'email' ],
orderBy: [
{ expr: {
switch: 'role',
cases: [
{ when: { value: 'admin' }, then: 1 },
{ when: { value: 'contributor' }, then: 2 }
],
default: 0
}, asc: true },
{ expr: {
cases: [ { when: { isNull: 'phone' }, then: 0 } ],
default: 1
}, desc: true },
{ expr: 'name', asc: true }
]
});
// (c): Function-based syntax
const result = await client.database('public').table('users').select({
fields: [ 'name', 'email' ],
orderBy: [
(q) => q.expr(
(r) => r.switch('role').cases(
(s) => s.when((t) => t.value('admin')).then(1),
(s) => s.when((t) => t.value('contributor')).then(2)
).default(3)
).asc(),
(q) => q.expr(
(r) => r.cases(
(s) => s.when((t) => t.isNull('phone')).then(0)
).default(1)
).desc(),
(q) => q.expr('name').asc()
]
});
Use the LIMIT
clause to limit the number of rows returned by a query.
Retrieve the first 3 books from the books table:
// (a): SQL syntax
const result = await client.query(
`SELECT
title,
author
FROM public.books
LIMIT 3`
);
// (b): Function-based syntax
const result = await client.database('public').table('books').select({
fields: ['title', 'author'],
limit: 3
});
Use the OFFSET
clause to skip a specified number of rows before returning rows.
Extend the previous to retrieve the next 3 books after skipping the first 3:
// (a): SQL syntax
const result = await client.query(
`SELECT
title,
author
FROM public.books
LIMIT 3 OFFSET 3`
);
// (b): Function-based syntax
const result = await client.database('public').table('books').select({
fields: ['title', 'author'],
limit: 3,
offset: 3
});
Using the JOIN
clause, select records from one table and tie in relevamt records from related tables.
Return a list of books with an extra dimension each: the author's name from the users
table:
// (a): SQL syntax
const result = await client.query(
`SELECT
books.title,
books.content,
usr.name AS author_name
FROM public.books
LEFT JOIN public.users AS usr ON books.author = usr.id
WHERE usr.role = $1`,
['admin']
);
// (b): Object-based syntax
const result = await client.database('public').table('books').select(
{ fields: [
[ 'books', 'title' ],
[ 'books', 'content' ],
{ expr: [ 'usr', 'name' ], as: 'author_name' }
], leftJoin: {
expr: ['public', 'users'], as: 'usr', on: [
{ eq: [['books', 'author'], ['usr', 'id'] ] }
]
}, where: [
{ eq: [ [ 'usr', 'role' ], { binding: ['admin'] } ] }
] }
);
// (c): Function-based syntax
const result = await client.database('public').table('books').select(
{ fields: [
(q) => q.expr([ 'books', 'title' ]),
(q) => q.expr([ 'books', 'content']),
(q) => q.expr([ 'usr', 'name' ]).as('author_name'),
], leftJoin: (q) => q.expr(['public', 'users']).as('usr').on(
(r) => r.eq(['books', 'author'], ['usr', 'id'])
), where: [
(q) => q.eq(['usr', 'role'], (r) => r.binding('admin'))
] }
);
Extend the previous to include another related info: the co-author's name from the users
table:
// (a): SQL syntax
const result = await client.query(
`SELECT
books.title,
books.content,
usr.name AS author_name,
usr2.name AS coauthor_name
FROM public.books
LEFT JOIN public.users AS usr ON books.author = usr.id
LEFT JOIN public.users AS usr2 ON books.coauthor = usr2.id
WHERE usr.role = $1`,
['admin']
);
// (b): Object-based syntax
const result = await client.database('public').table('books').select(
{ fields: [
[ 'books', 'title' ],
[ 'books', 'content' ],
{ expr: [ 'usr', 'name' ], as: 'author_name' },
{ expr: [ 'usr2', 'name' ], as: 'coauthor_name' }
], joins: [
{ type: 'LEFT_JOIN', expr: ['public', 'users'], as: 'usr', on: [
{ eq: [['books', 'author'], ['usr', 'id'] ] }
] },
{ type: 'LEFT_JOIN', expr: ['public', 'users'], as: 'usr2', on: [
{ eq: [['books', 'coauthor'], ['usr2', 'id'] ] }
] }
], where: [
{ eq: [ [ 'usr', 'role' ], { binding: ['admin'] } ] }
] }
);
// (c): Function-based syntax
const result = await client.database('public').table('books').select(
{ fields: [
(q) => q.expr([ 'books', 'title' ]),
(q) => q.expr([ 'books', 'content']),
(q) => q.expr([ 'usr', 'name' ]).as('author_name'),
], joins: [
(q) => q.type('LEFT_JOIN').expr(['public', 'users']).as('usr').on(
(r) => r.eq(['books', 'author'], ['usr', 'id'])
),
(q) => q.type('LEFT_JOIN').expr(['public', 'users']).as('usr2').on(
(r) => r.eq(['books', 'coauthor'], ['usr2', 'id'])
)
], where: [
(q) => q.eq(['usr', 'role'], (r) => r.binding('admin'))
] }
);
Use the GROUP BY
clause to group rows together by specific criteria for use with aggregate functions.
Count the number of books written by each author:
// (a): SQL syntax
const result = await client.query(
`SELECT author, COUNT(*) AS total_books
FROM public.books
GROUP BY author`
);
// (b): Object-based syntax
const result = await client.database('public').table('books').select(
{ fields: [
{ expr: 'author' },
{ expr: {
fn: ['COUNT', '*']
}, as: 'total_books' }
], groupBy: ['author'] }
);
// (c): Function-based syntax
const result = await client.database('public').table('books').select(
{ fields: [
(q) => q.expr('author'),
(q) => q.expr(
(r) => r.fn('COUNT', '*')
).as('total_books')
], groupBy: ['author'] }
);
Use the HAVING
clause to filter groups based on the result of aggregate functions.
Limit the results of the previous to only authors with more than 5 books:
// (a): SQL syntax
const result = await client.query(
`SELECT author, COUNT(*) AS total_books
FROM public.books
GROUP BY author
HAVING COUNT(*) > 5`
);
// (b): Object-based syntax
const result = await client.database('public').table('books').select(
{ fields: [
{ expr: 'author' },
{ expr: {
fn: ['COUNT', '*']
}, as: 'total_books' }
], groupBy: ['author'], having: [
{ gt: [{ fn: ['COUNT', '*'] }, 4] }
] }
);
// (c): Function-based syntax
const result = await client.database('public').table('books').select(
{ fields: [
(q) => q.expr('author'),
(q) => q.expr(
(r) => r.fn('COUNT', '*')
).as('total_books')
], groupBy: ['author'], having: [
(q) => q.gt((r) => r.fn('COUNT', '*'), 4)
] }
);
Using the WINDOW
clause, define reusable window specifications for window functions, enabling consistent and concise definitions across multiple functions in a query.
Do a little statistics on the books table: for each book, get the daily engagement score on the day book was published:
// (a): SQL syntax
const result = await client.query(
`SELECT
title,
content,
RANK(num_views ORDER BY content ASC) OVER window_1 AS engagement_score,
FROM public.books
WINDOW window_1 AS (
PARTITION BY created_at
ORDER BY title ASC
)`
);
// (b): Object-based syntax
const result = await client.database('public').table('books').select(
{ fields: [
{ expr: 'title' },
{ expr: 'content' },
{ expr: {
fn: ['RANK', 'num_views'], over: 'window_1', orderBy: { expr: 'content', asc: true }
}, as: 'engagement_score' }
], window: [
{ name: 'window_1', partitionBy: 'created_at', orderBy: [
{ expr: 'title', asc: true }
] }
] }
);
// (c): Function-based syntax
const result = await client.database('public').table('books').select(
{ fields: [
(q) => q.expr('title'),
(q) => q.expr('content'),
(q) => q.expr(
(r) => r.fn('RANK', 'num_views').over('window_1').orderBy((s) => s.expr('content').asc())
).as('engagement_score')
], window: [
(q) => q.name('window_1').partitionBy('created_at').orderBy(
(r) => r.expr('title').asc()
)
] }
);
While you could stitch relevant SQL functions together to structure your output data, Linked QL supports special JSON-like syntaxes that abstract the rough work. (See ➞ JSON Sugars
.)
Return output fields in specific formats:
// (a): SQL syntax
const result = await client.query(
`SELECT
name,
phone,
{ email, phone AS mobile } AS contact1,
[ email, phone ] AS contact2
FROM public.users`
);
// (b): Object-based syntax
const result = await client.database('public').table('users').select({
fields: [
{ expr: 'name' },
{ expr: 'phone' },
{ expr: {
fields: ['email', { expr: 'phone', as: 'mobile'}]
}, as: 'contact1' },
{ expr: {
items: ['email', 'phone']
}, as: 'contact2' }
]
});
// (c): Function-based syntax
const result = await client.database('public').table('users').select({
fields: [
(q) => q.expr('name'),
(q) => q.expr('phone'),
(q) => q.expr(
(r) => r.fields('email', (s) => s.expr('phone').as('mobile'))
).as('contact1'),
(q) => q.expr(
(r) => r.items('email', 'phone')
).as('contact2')
]
});
While you could use the traditional JOIN approach to query relational data, Linked QL supports special path operators that let you express relationships graphically. (See ➞ Magic Paths
.)
Return a list of books with an extra dimension each: the author's name from the users
table:
// (a): SQL syntax
const result = await client.query(
`SELECT
title,
content,
author ~> name AS author_name
FROM public.books
WHERE author ~> role = $1`,
['admin']
);
// (b): Object-based syntax
const result = await client.database('public').table('books').select(
{ fields: [
{ expr: 'title' },
{ expr: 'content' },
{ expr: {
path: ['author', '~>', 'name']
}, as: 'author_name' }
], where: [
{ eq: [
{ path: ['author', '~>', 'role'] },
{ binding: ['admin'] }
] }
] }
);
// (c): Function-based syntax
const result = await client.database('public').table('books').select(
{ fields: [
(q) => q.expr('title'),
(q) => q.expr('content'),
(q) => q.expr(
(r) => r.path('author', '~>', 'name')
).as('author_name')
], where: [
(q) => q.eq(
(r) => r.path('author', '~>', 'role'),
(r) => r.binding('admin')
)
] }
);
Extend the previous to include another related info: the co-author's name from the users
table:
// (a): SQL syntax
const result = await client.query(
`SELECT
title,
content,
author ~> name AS author_name,
coauthor ~> name AS coauthor_name
FROM public.books
WHERE author ~> role = $1`,
['admin']
);
// (b): Object-based syntax
const result = await client.database('public').table('books').select(
{ fields: [
{ expr: 'title' },
{ expr: 'content' },
{ expr: {
path: ['author', '~>', 'name']
}, as: 'author_name' },
{ expr: {
path: ['coauthor', '~>', 'name']
}, as: 'coauthor_name' }
], where: [
{ eq: [
{ path: ['author', '~>', 'role'] },
{ binding: ['admin'] }
] }
] }
);
// (c): Function-based syntax
const result = await client.database('public').table('books').select(
{ fields: [
(q) => q.expr('title'),
(q) => q.expr('content'),
(q) => q.expr(
(r) => r.path('author', '~>', 'name')
).as('author_name'),
(q) => q.expr(
(r) => r.path('coauthor', '~>', 'name')
).as('coauthor_name')
], where: [
(q) => q.eq(
(r) => r.path('author', '~>', 'role'),
(r) => r.binding('admin')
)
] }
);
Return a list of books with an extra dimension each: details of the author:
// (a): SQL syntax
const result = await client.query(
`SELECT
title,
content,
author: { name, email } AS author
FROM public.books
WHERE author ~> role = $1`,
['admin']
);
// (b): Object-based syntax
const result = await client.database('public').table('books').select(
{ fields: [
{ expr: 'title' },
{ expr: 'content' },
{ expr: {
rpath: ['author', { fields: ['name', 'email'] }]
}, as: 'author' }
], where: [
{ eq: [
{ path: ['author', '~>', 'role'] },
{ binding: ['admin'] }
] }
] }
);
// (c): Function-based syntax
const result = await client.database('public').table('books').select(
{ fields: [
(q) => q.expr('title'),
(q) => q.expr('content'),
(q) => q.expr(
(r) => r.rpath('author', (s) => s.fields('name', 'email'))
).as('author'),
], where: [
(q) => q.eq(
(r) => r.path('author', '~>', 'role'),
(r) => r.binding('admin')
)
] }
);