首页 > 解决方案 > Haskell + Squeal 中的 SQL 数组聚合

问题描述

我在 Haskell 中使用了一个名为Squeal的 SQL 库。

在 Squeal 库中将多个文本行聚合到一个数组中的正确方法是什么?

假设我有一个非常简单的架构,其中只有一个包含列“关键字”(PG 文本类型)+ 关联类型的表:

import           Squeal.PostgreSQL
import qualified GHC.Generics                  as GHC
import qualified Generics.SOP                  as SOP

type Constraints = '["pk_keywords"  ::: 'PrimaryKey '["id"]]
type Columns
  = '["id" ::: 'Def :=> 'NotNull 'PGint8, "keyword" ::: 'NoDef :=> 'NotNull 'PGtext]
type Table = 'Table (Constraints :=> KColumns)
type Schema = '["keywords" ::: Table]
type Schemas = '["public" ::: Schema]

newtype Keywords = Keywords {unKeywords ::  [Text]} deriving (GHC.Generic)
instance SOP.Generic Keywords
instance SOP.HasDatatypeInfo Keywords
type instance PG Keywords = 'PGvararray ( 'NotNull 'PGtext)

这是我需要帮助的部分:

我正在尝试这样的聚合查询:

keywords :: Query_ Schemas () Keywords
keywords =
  select_ ((arrayAgg (All #keyword)) `as` #fromOnly) (from (table #keywords))

但是,我不断收到错误消息:

* Couldn't match type 'NotNull (PG [Text])
                 with 'Null ('PGvararray ty0)
    arising from a use of `as'

据我了解,arrayAgg可以产生NULL,所以我需要从这里 []以某种方式提供一个默认的空数组: https ://hackage.haskell.org/package/squeal-postgresql-0.5.1.0/docs/Squeal-PostgreSQL-Expression- Null.html#v:fromNullfromNull

但我不太清楚如何提供。

值类型不匹配(PG [Text]vs 'PGvararray ty0)呢?如何解决?

标签: sqlpostgresqlhaskell

解决方案


为了记录,图书馆的作者提供了一个解决方案,如下所示:

keywords :: Query_ Schemas () (Only (VarArray [Text]))
keywords = select_
  (fromNull (array [] & inferredtype) (arrayAgg (All #keyword)) `as` #fromOnly)
  (from (table #keywords) & groupBy Nil)

这里的关键因素是:

  1. 提供一个默认的空数组fromNull (array [] & inferredtype) ...。这样我们可以避免Maybe在返回类型中使用
  2. 提供分组groupBy Nil
  3. 选择其中一个DistinctAllarrayAgg
  4. 最后,返回类型应该是VarArray x

推荐阅读