Поддержка функции array_agg, специфичной для PostgreSQL, в рамках scala?

Существует ли какая-то структура реляционной базы данных scala (anorm, squeryl и т. д.), использующая агрегаторы, подобные postgres, для создания списков после группировки или, по крайней мере, имитации ее использования?

Я бы ожидал двух уровней реализации:

  • «стандартный», где по крайней мере любая группировка SQL с array_agg транслируется в список того типа, который агрегируется,

  • и "Scala ORM", где разрешен некоторый тип соединения, так что, если агрегация является внешним ключом для другой таблицы, создается список элементов другой таблицы. Конечно, эта последняя вещь находится за пределами досягаемости SQL, но если я использую более мощный язык, я не возражаю против некоторых стероидов.

Я нахожу особенно интригующим тот факт, что документация slick, основанная именно на разрешении нотации scala group-by, по-видимому, явно отрицает вывод списков в результате группировки.

РЕДАКТИРОВАТЬ: вариант использования

У вас есть типичная таблица «многие ко многим», скажем, для продуктов и поставщиков, пар (p_id, s_id). Вы хотите создать список поставщиков для каждого продукта. Таким образом, запрос postgresql должен быть

SELECT p_id, array_agg(s_id) from t1 group by p_id

Можно было бы ожидать какого-то идиоматического способа сделать это в slick, но я не понимаю, как это сделать. Кроме того, если мы перейдем к какой-либо ORM, то мы могли бы также рассмотреть соединение с таблицами products и Suppliers, по p_id и s_id соответственно, и получить в качестве ответа zip (product, (supplier1, supplier2, supplierN)), содержащий объекты и не только идентификаторы


person arivero    schedule 19.01.2015    source источник
comment
Кстати. даже без агрегации возможность интерпретировать внешний ключ как ссылку на другой объект должна быть приятным плюсом.   -  person arivero    schedule 19.01.2015
comment
Результат array_agg имеет тип Array в JDBC, поэтому с помощью Anorm вы можете анализировать такой столбец как Array[T] или List[T] при условии, что каждое значение массива имеет поддерживаемый тип, который может быть проанализирован как T. У Slick должно быть что-то похожее с собственным запросом.   -  person cchantep    schedule 19.01.2015
comment
Я думал, что Slick мог бы добавить к этому некоторый синтаксис. Они постоянно говорят, что .group-by всегда должен завершаться картой плюс и агрегатором (скажем, avg), чтобы избежать создания списков. Но в postgresql естественно создавать списки, поэтому неагрегированный групповой запрос в Slick должен/может компилироваться в array_agg   -  person arivero    schedule 19.01.2015
comment
Это своего рода случай, когда я предпочитаю обрабатывать специфику БД с помощью специального анализатора результатов (Anorm).   -  person cchantep    schedule 20.01.2015


Ответы (3)


Я также не уверен, правильно ли я понял ваш вопрос, не могли бы вы уточнить?

В настоящее время в slick вы не можете использовать postgres «array_agg» или «string_agg» в качестве метода для типа Query. Если вы хотите использовать эту конкретную функцию, вам нужно использовать пользовательский sql. Но: некоторое время назад я добавил задачу (https://github.com/slick/slick/issues/923, вы должны следить за этим обсуждением), и у нас есть готовый прототип от cvogt для этого.

В прошлом мне нужно было использовать «string_agg», и я добавил для него патч (см. .com/mobiworx/slick/commit/486c39a7ed90c9ccac356dfdb0e5dc5c24e32d63), так что, возможно, это будет вам полезно. Посмотрите на "AggregateTest", чтобы узнать больше об этом.

Другая возможность состоит в том, чтобы инкапсулировать использование «array_agg» в представлении базы данных и просто использовать это представление с slick. Таким образом, вам не нужен «array_agg» непосредственно в slick.

person tfh    schedule 26.01.2015

Вы можете использовать slick-pg.

Он поддерживает array_agg и другие агрегатные функции.

person Daniel Shin    schedule 04.11.2016

Ваш вопрос интригует, не могли бы вы немного рассказать о том, как это могло бы выглядеть в идеале? Когда вы group by у вас часто есть дополнительный столбец, такой как count(*) помимо стандартных столбцов из вашего класса case, так каким же будет тип вашего списка?

Большинство моих (анорма) методов либо возвращают одноэлементный элемент (возможно, Option), либо список типа этого класса. Для каждого класса case у меня есть переменная sqlFields (например, m.id, m.name, m.forManufacturer) и одна переменная анализатора, на которую я ссылаюсь как на .as(modelParser.singleOpt), так и на .as(modelParser *). Для внешних ключей lazy val на уровне класса case (или def, если это необходимо) очень полезно. Например. если бы у меня были объекты Модель и Производитель с внешним ключом forManufacturer в Модели, тогда я мог бы определить lazy val manufacturer : Manufacturer = ... в классе case модели, чтобы в любое время я мог ссылаться на model.manufacturer. Я могу определить объединения как их собственные методы, либо таким образом, либо как методы в сопутствующем объекте.

Не на 100% уверен, что отвечаю на ваш вопрос, но подумал, что это немного длинно для комментария.

Редактировать: если ваш драйвер поддерживает синтаксический анализ массивов postgresql, вы можете напрямую сопоставить их с классом, например ProductSuppliers(id:Int, suppliers:List[Int]) (или даже List[Supplier]?) В анорме, который, я думаю, настолько идиоматичен, насколько это возможно? Для баз данных, которые его не поддерживают, мне кажется, что это похоже на версию order by, то есть select p1, s1 from t1 order by p1, которую вы могли бы groupBy p1 и аналогичным образом сопоставить с ProductSuppliers.

person wwkudu    schedule 19.01.2015
comment
Правда я не знаю, насколько sql-стандартной является функция array_agg, вы с ней знакомы? Дополнительный столбец преобразуется в список. Теперь, в гладком и, вероятно, в анорме, я просто ожидал бы способ создавать такие списки и не более того. В структуре ORM, если бы тип списка был внешним ключом для другой таблицы, я бы ожидал, что список будет преобразован в список объектов другой таблицы. - person arivero; 19.01.2015