Гладкий простой sql запрос с нумерацией страниц - PullRequest
0 голосов
/ 29 января 2020

У меня есть что-то вроде этого, используя Akka, Alpakka + Slick

 Slick
 .source(
     sql"""select #${onlyTheseColumns.mkString(",")} from #${dbSource.table}"""
    .as[Map[String, String]]
    .withStatementParameters(rsType = ResultSetType.ForwardOnly, rsConcurrency = ResultSetConcurrency.ReadOnly, fetchSize = batchSize)
    .transactionally
).map( doSomething )...

Я хочу обновить этот простой sql запрос, пропустив первый N-й элемент. Но это очень специфично для БД c.

Возможно ли получить бит разбиения на страницы, сгенерированный Slick? [например, для безопасных по типу запросов можно просто сделать сброс, отфильтровать, взять?]

ps: у меня нет схемы, поэтому я не могу go безопасный тип, просто хочу все таблицы как карта, фильтр, дроп и пр. c на них. ps2: на уровне akka, flow.drop работает, но он не оптимален / медленен, потому что он все еще потребляет строки. Приветствия

Ответы [ 3 ]

0 голосов
/ 01 апреля 2020

в зависимости от вашей базы данных, вы можете использовать что-то вроде

val page = 1
val pageSize = 10
val query = sql"""
  select #${onlyTheseColumns.mkString(",")} 
  from #${dbSource.table} 
  limit #${pageSize + 1}
  offset #${pageSize * (page - 1)}
"""

, часть pageSize+1 сообщает вам, существует ли следующая страница

0 голосов
/ 01 апреля 2020

Я хочу обновить этот простой sql запрос, пропустив первый N-й элемент. Но это очень специфично для БД: c.

Поскольку вы беспокоитесь об изменении SQL для разных баз данных, я предлагаю вам абстрагироваться от этой части SQL и решить, что делать на основе используемого профиля Slick.

Если вы работаете с несколькими продуктами баз данных, вы, вероятно, уже абстрагировались от какого-либо определенного c профиля, возможно, используя JdbcProfile. В этом случае вы можете поместить своего помощника "skip N elements" в класс и использовать активный slickProfile, чтобы выбрать SQL для использования. (В качестве альтернативы вы, конечно, можете проверить с помощью других средств, например, заданного вами значения среды).

На практике это может быть что-то вроде этого:

case class Paginate(profile: slick.jdbc.JdbcProfile) {
  // Return the correct LIMIT/OFFSET SQL for the current Slick profile
  def page(size: Int, firstRow: Int): String =
    if (profile.isInstanceOf[slick.jdbc.H2Profile]) {
      s"LIMIT $size OFFSET $firstRow"
    } else if (profile.isInstanceOf[slick.jdbc.MySQLProfile]) {
      s"LIMIT $firstRow, $size"
    } else {
      // And so on... or a default
      // Danger: I've no idea if the above SQL is correct - it's just placeholder
      ???
    }
}

Что вы можете сделать используйте как:

// Import your profile
import slick.jdbc.H2Profile.api._

val paginate = Paginate(slickProfile)

val action: DBIO[Seq[Int]] = 
  sql""" SELECT cols FROM table #${paginate.page(100, 10)}""".as[Int]

Таким образом, вы можете изолировать (и контролировать) спецификацию СУБД c SQL в одном месте.

Чтобы сделать помощника более удобным, и поскольку slickProfile подразумевается, вы могли бы вместо этого написать:

def page(size: Int, firstRow: Int)(implicit profile: slick.jdbc.JdbcProfile) = 
    // Logic for deciding on SQL goes here

Я чувствую себя обязанным прокомментировать, что использование соединения (#$) в простом SQL открывает вам для SQL атак инъекцией, если любое из значений предоставляется пользователем.

0 голосов
/ 29 января 2020

Поскольку вы используете простой SQL, вы должны предоставить работоспособный SQL во фрагменте кода. Обычный SQL может быть небезопасным, но agile.

Кстати, самый оптимальный способ - пропустить N-й элемент по базе данных, например, предел в mysql.

...