Также спросил на GitHub.
Хочу использовать union в МикроОРМ. Кажется, нет встроенного способа (например, qb.union()
, поэтому я думаю, что мне нужно либо запустить необработанную команду SQL (через qb.raw()
), либо использовать Knex для создания команды.
Например, я хочу получить несколько строк из таблицы на основе некоторого условия, однако в любом случае вернуть как минимум две строки с наибольшим идентификатором.
(
select * from sch.tbl
-- where -- insert some condition, e.g. `id > 10`
order by id desc
) union (
select * from sch.tbl order by id desc limit 2
) order by id asc;
что, я полагаю, может быть выполнено с помощью Knex следующим образом:
this.orm.em.getKnex()
.union(qb => qb
.select('*')
.withSchema('sch')
.from('tbl')
.where('id', '>', 10)
.orderBy('id', 'DESC')
.limit(10)
)
.union(qb => qb
.select('*')
.withSchema('sch')
.from('tbl')
.orderBy('id', 'DESC')
.limit(2)
)
.orderBy('id', 'ASC')
Однако я понятия не имею, как получить результат.
Когда я запускаю следующее:
qb.raw('(select * from ?.? where id > ? order by id desc limit 10) union (select * from ?.? order by id desc limit 2) order by id asc', ['sch', 'tbl', 10, 'sch', 'tbl'])
он строит запрос (вывод qb.getQuery()
) select "s0".* from "sch"."tbl" as "s0"
, а это не то, что я хотел.
Спасибо за вашу помощь!
Обновлять
Я могу использовать следующее, однако, когда я использую заполнители ?
, происходит сбой, поскольку он заменяет их на $1
(1
увеличивается). Однако он работает без заполнителей, как и ожидалось.
const knex = this.orm.em.getKnex()
// This fails
const result = await knex.raw('(select * from ?.? where id > ? order by id desc limit 10) union (select * from ?.? order by id desc limit 2) order by id asc', ['sch', 'tbl', 10, 'sch', 'tbl'])
// Error
error: (select * from $1.$2 where id > $3 order by id desc limit 10) union (select * from $4.$5 order by id desc limit 2) order by id asc - syntax error at or near "$1"
// This works
const x = await knex.raw('(select * from sch.tbl where id > 10 order by id desc limit 10) union (select * from sch.tbl order by id desc limit 2) order by id asc', ['sch', 'tbl', 10, 'sch', 'tbl'])
Хотя я бы предпочел некоторые синтаксические сахарные команды (либо в MikroORM, либо в Knex), необработанные SQL-команды — хороший обходной путь, однако я хочу использовать заполнители (привязки). Как я могу это сделать?
Обновление 2
Хорошо, я пропустил примечание в документации Knex о том, что ?
интерпретируется как значение, а ??
как идентификатор.
Кроме того, я нашел решение с помощью Knex (хотя я использую его от MikroORM):
const knex = this.orm.em.getKnex()
const xKnexRaw = knex
.withSchema('sch')
.select('*')
.from('tbl')
.where('id', '>', 10)
.orderBy('start_time', 'desc')
.limit(10)
.union(
qb => qb
.select('*')
.withSchema('sch')
.from('tbl')
.orderBy('id', 'desc')
.limit(2),
true
)
.orderBy('start_time', 'asc')
// `res` is a result (array of row) without TypeScript types
const res = await this.orm.em.getConnection().execute(query)
// `entities` is a result (array of entities) with mapped TypeScript types
const entities = res.map(e => this.orm.em.map(StatusInterval, e))
Это решение с использованием Knex (хотя я использую его от MikroORM):
const knex = this.orm.em.getKnex()
const query = knex
.withSchema('sch')
.select('*')
.from('tbl')
.where('id', '>', 10)
.orderBy('start_time', 'desc')
.limit(10)
.union(
qb => qb
.select('*')
.withSchema('sch')
.from('tbl')
.orderBy('id', 'desc')
.limit(2),
true
)
.orderBy('start_time', 'asc')
// `res` is a result (array of row) without TypeScript types
const res = await this.orm.em.getConnection().execute(query)
// `entities` is a result (array of entities) with mapped TypeScript types
const entities = res.map(e => this.orm.em.map(StatusInterval, e))