回答

收藏

具有has_many关系的订单

技术问答 技术问答 186 人阅读 | 0 人回复 | 2023-09-13

我有Articles那个have_many Metrics。我希望Articles在Metric.name =“score”时按特定的Metric.value排序。(Metric将各种文章统计信息记录为“名称”和“值”对。一个文章可以具有多个度量标准,甚至可以包含多个“得分”,尽管我只对最新的排序感兴趣。)  b: m) [  k6 w8 L
class Article7 [7 h- v& I/ @  _) N' a  A& g. W
  has_many :metrics7 W) {: {& l/ Y. Y
class Metric
: }! r3 f6 T8 ^  S# K  #  name       :string(255)/ D* T  e% l1 T4 Y7 ^
  #  value      :decimal(, )
6 ^. R  n( u/ V8 s7 B  belongs_to :article
$ X* b% s: X: ]2 Z* q我正在努力写一个范围来做到这一点-有什么想法吗?像这样吗?8 n6 G( t! B2 ^# i
scope :highest_score, joins(:metrics).order('metrics.value DESC')# A) }1 A9 w# c& v: B
                      .where('metrics.name = "score"')
: U' N. @( z( c# `更新:: T: U2 i( {- [8 k" ]8 r' z# v2 T$ a# ^

5 B* Y  x* K8 ]/ }6 }! E$ U' T文章可能在metrics表中存储了许多“得分” (因为它们是每周/每月/每年等计算的),但我只对使用任何文章的第一个(最新)“得分”感兴趣。该Metric模型具有一个default_scope,以确保按DESCending排序。
2 _: \+ e( o- |( M! W/ z- p% P% f5 Y: V
修复了“ metrics.value DESC”报价位置上的错字。
: n2 R: p. D; S3 m8 C: i, G$ w( Z, V# i+ [
与我的手机友uber rails黑客交谈,看来我需要一个原始的SQL查询。现在,我不知所措…(如果有帮助,我正在使用Postgres。)
' F0 e7 a& B' R# j/ P8 l. s7 G/ w- m2 d" b7 b& \9 R* M
5 I% L* h! K, z( c, O9 c
谢谢!
, V3 a% G, j8 e) C9 t6 X. w' r更新2:
# ~" M4 _4 f4 h" |7 S9 K" X. Q/ ]多亏了Erwin的出色SQL查询建议,我有了一个可以正常工作的原始SQL查询:
0 Y4 d6 ^* O: ]0 BSELECT a.*6 Z" d7 Y$ O  g! {' A, U6 k1 n7 h
FROM   articles a
9 u( @. F7 y( p( N( {3 `LEFT   JOIN (  i4 L5 j- ]+ ?& w# l
   SELECT DISTINCT ON (article_id)5 E6 ]0 ^! A. l! G3 y
          article_id, value1 Y: s9 _2 G5 Q/ B/ d. J  B2 y
   FROM   metrics m
6 h3 H+ s& a- W5 j% Q9 N   WHERE  name = 'score'
- B0 W8 s  P* P" _& e   ORDER  BY article_id, date_created DESC
8 J5 B+ K1 m0 i8 e0 ?- P) Q9 V   ) m ON m.article_id = a.id9 P& h; X  q+ X  M6 ?
ORDER  BY m.value DESC;& `: ^9 q5 D9 n2 q' g) t( a
article_list_by_desc_score = ActiveRecord::Base.connection.execute(sql)% S( S' d$ @6 q" B
这给出了代表商品数据的散列数组(而不是商品对象?)。
% Q+ x) V2 `- e; \$ {后续问题:
9 H& O2 g- f$ }: f& W有什么方法可以将其转换回对Rails的activerecord查询中?(这样我就可以在范围内使用它了)
+ c6 f# }% Q$ R) i: Q解决方案更新:% k- \( {5 n, c% y  s
万一有人在寻找最终的ActiveRecord查询-$ W8 ]8 i4 G5 K: W4 {9 U
非常感谢Mattherick在这个问题上给我的帮助。最终的工作查询是:
1 f' A: t. k$ g% j9 Q. T0 jscope :highest_score, joins(:metrics).where("metrics.name"
' I' a' Q* P" m0 z; L      => "score").order("metrics.value desc").group("metrics.article_id",
7 M% h4 l. K3 s1 ], h( g7 e2 Y      "articles.id", "metrics.value", "metrics.date_created")" P: |( q  O9 V6 p) F
      .order("metrics.date_created desc")
" ^8 m5 A( i+ b" w: W8 j6 P  q7 M谢谢大家!
, ]( r1 Y0 k" N' O: l; z* D. D               
4 c' y! Z. k% d" ]: Y& D解决方案:& s4 w: _! a6 c/ f6 c. }7 u
               
" k3 E" F! S; Y1 t
/ o) F# Z6 t7 f) _2 \
/ ?5 ?& D8 i. B; {                该查询可以像这样工作:  k3 w5 k. Z1 ~: M$ i4 T4 L
SELECT a.*8 e4 c5 h  Y* B- C" @
FROM   article a; O9 y8 e: p  a6 {& ]
LEFT   JOIN (# a  J$ I. e- }3 P2 r6 |
   SELECT DISTINCT ON (article_id)( `' B. C& R, G1 f: J
          article_id, value
; _$ M4 ^( D1 b% O& I3 W   FROM   metrics m
; p7 R  |( q5 j0 e- ~6 Z% U/ I  o   WHERE  name = 'score'% c$ H: t  P4 o; }* Q0 Q
   ORDER  BY article_id, date_created DESC- D6 q$ F% t$ V: j6 r
   ) m ON m.metrics_id = a.metrics_id
* m6 U: b. t" V1 o- z5 UORDER  BY m.value DESC;
3 M+ ]9 \. ]/ n. T* s4 h首先 ,检索“最近”value的name = 'score'每一篇文章中的子查询m。在此相关答案中对所用技术的更多说明:
3 Q, C, G. L( D# ]3 O3 H在每个GROUP BY组中选择第一行?
: S. F  @+ w3 y  }5 O4 S
  K6 ^, r0 F, A4 r) O
但是,您似乎是一个非常基本的误解的受害者:0 Z) S7 e- V9 Z1 |. Q9 E3 r
) g' l$ |+ n* q- M/ s- h2 R
但我只想对任何一篇文章使用最早发现的(最新的)“评分”。指标模型具有一个default_scope,以确保按DESCending排序。
  O' \7 l4 ^0 m# }0 Z$ ~4 A0 U' V* ?
没有“自然秩序” 在表中。在中SELECT,您需要ORDER BY定义明确的条件。出于此查询的目的,我假设使用column
) T) f0 ~$ {7 H5 b. ]7 qmetrics.date_created。如果您一无所获,则 无法 定义“最新”,并被迫从多个限定行退回到任意选择:
) p& y! ?* j8 f& r8 e9 v   ORDER  BY article_id
. y* T* g$ J" z$ l/ h% _这是 不 可靠的。Postgres将选择一行。可能会随着对表的任何更新或查询计划中的任何更改而更改。6 H$ M8 p  y3 q9 z7 n
接下来 ,LEFT JOIN到表article和ORDER BY value。NULL排在最后,因此没有合格价值的文章排在最后。
& h$ z2 }9 k9 ?注意:一些不太聪明的ORM(恐怕Ruby的ActiveRecord就是其中之一)使用非描述性和非区别性 id. h7 s; ]3 d# e* Z, p5 Z
作为主键的名称。您必须适应您未提供的实际列名。
! w4 t1 j* t" K4 M1 R% X表现: q# n8 v5 s) L$ ^
应该得体。就Postgres而言,这是一个“简单”的查询。表上的部分多列索引metrics可以使其更快:
$ ~4 g7 ^5 \& o7 Z/ @3 ?/ i1 KCREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created)
" O3 J6 P" k6 n5 w1 x% {WHERE name = 'score';& f7 f; t( O- l4 A, i+ k
列按此顺序。在PostgreSQL 9.2+中,您可以添加列值以使仅索引扫描成为可能:
) D# }4 K/ M8 gCREATE INDEX metrics_some_name_idx ON metrics(article_id, date_created, value)
5 \$ E8 Z8 f# Q# s, U, UWHERE name = 'score';
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则