查询m:n关系中的所有n个元素

b5lpy0ml  于 2021-07-27  发布在  Java
关注(0)|答案(2)|浏览(337)

假设我有以下表格,这些表格是附加到文章的模型标签:

articles (article_id, title, created_at, content)
tags (tag_id, tagname)
articles_tags (article_fk, tag_fk)

检索数据的惯用方法是什么 n 最新的文章和他们所有的附加标签名称?这似乎是一个标准问题,但我对sql还是新手,不知道如何优雅地解决这个问题。
从应用程序的Angular 来看,我想编写一个函数,返回表单的记录列表 [title, content, [tags]] ,也就是说,一篇文章的所有标签都包含在一个可变长度的列表中。sql关系没有那么灵活;到目前为止,我只能考虑一个查询来连接表,该表为每个项目/标记组合返回一个新行,然后我需要以编程方式将其压缩为上述形式。
或者,我可以想出一个解决方案,其中我提出两个问题:第一,对于文章;第二,一个 inner join 在链接表和标记表上。然后,在应用程序中,我可以为每个 article_id 获取给定文章的所有标签?后者似乎是一个相当冗长和低效的解决方案。
我错过什么了吗?有没有一种规范的方法来表达一个查询?还是一个查询加上少量的后处理?
除了简单的sql问题之外,opalyedsl中相应的查询是什么样子的?也就是说,如果可以翻译的话?

f2uvfpb9

f2uvfpb91#

您通常会使用行限制查询来选择项目并按降序日期对其排序,并使用带有聚合函数的联接或相关子查询来生成标记列表。
以下查询提供了10篇最近的文章,以及它们在数组中的相关标记的名称:

select 
    a.*,
    (
        select array_agg(t.tagname) 
        from article_tags art
        inner join tags t on t.tag_id = art.tag_fk
        where art.article_fk = a.article_id
    ) tags
from articles
order by a.created_at desc
limit 10
xzabzqsa

xzabzqsa2#

您已经成功地将gmb的大部分答案转换为后续问题的答案中的opaleye。这是一个完整的工作版本在猫眼石。
今后,欢迎您在opaleye的issue tracker上提出此类问题。你可能会得到更快的React。

{-# LANGUAGE Arrows #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TemplateHaskell #-}

import           Control.Arrow
import qualified Opaleye as OE
import qualified Data.Profunctor as P
import           Data.Profunctor.Product.TH (makeAdaptorAndInstance')

type F field = OE.Field field

data TaggedArticle a b c =
  TaggedArticle { articleFk :: a, tagFk :: b, createdAt :: c}
type TaggedArticleR = TaggedArticle (F OE.SqlInt8) (F OE.SqlInt8) (F OE.SqlDate)

data Tag a b = Tag { tagKey :: a, tagName :: b }
type TagR = Tag (F OE.SqlInt8) (F OE.SqlText)

$(makeAdaptorAndInstance' ''TaggedArticle)
$(makeAdaptorAndInstance' ''Tag)

tagsTable :: OE.Table TagR TagR
tagsTable = error "Fill in the definition of tagsTable"

taggedArticlesTable :: OE.Table TaggedArticleR TaggedArticleR
taggedArticlesTable = error "Fill in the definition of taggedArticlesTable"

-- | Query all tags.
allTagsQ :: OE.Select TagR
allTagsQ = OE.selectTable tagsTable

-- | Query all article-tag relations.
allTaggedArticlesQ :: OE.Select TaggedArticleR
allTaggedArticlesQ = OE.selectTable taggedArticlesTable

-- | Join article-ids and tag names for all articles.
articleTagNamesQ :: OE.Select (F OE.SqlInt8, F OE.SqlText, F OE.SqlDate)
articleTagNamesQ = proc () -> do
  ta <- allTaggedArticlesQ -< ()
  t  <- allTagsQ -< ()
  OE.restrict -< tagFk ta OE..=== tagKey t -- INNER JOIN ON
  returnA -< (articleFk ta, tagName t, createdAt ta)

-- | Aggregate all tag names for all articles
articleTagsQ :: OE.Select (F OE.SqlInt8, F (OE.SqlArray OE.SqlText))
articleTagsQ =
  OE.aggregate ((,) <$> P.lmap (\(i, _, _) -> i) OE.groupBy
                    <*> P.lmap (\(_, t, _) -> t) OE.arrayAgg)
      (OE.limit 10 (OE.orderBy (OE.desc (\(_, _, ca) -> ca)) articleTagNamesQ))

相关问题