0

大規模ですが、やや単純な SQL クエリがあります。基本的に、私のサイトのユーザーは、レビューを書いたり、コメントを残したり、データベースにエントリを追加したりするなど、さまざまな種類の活動に対して評判を築いています. ほとんどの場合、これらのポイントは reputable_actions テーブルに格納されており、reputable_actions テーブルを繰り返し LEFT JOIN することでそれらを取得します。これはずさんな感じがしますが、ほとんどの場合うまくいきます。

私が経験している問題は、「レビュアー」と「コミュニティ」という 2 つのレピュテーションに関するものです。他のものとは異なり、reputable_actions テーブルには保存されません。代わりに、それらの値は、最初にコメント テーブルを LEFT JOIN することによってアクセスする、votes テーブルから派生します。何らかの理由で、コメント テーブルに参加すると、他のすべての評判が指数関数的に増加します。ある試行では、「アーキビスト」の評価は 25 と想定されていましたが、私がコメントに参加すると、10050 に膨れ上がりました。

私は SQL の初心者で、知っていること (つまり、users.id に GROUP BY 句を適用すること) を試しましたが、まだ運がありませんでした。いくつかのガイダンスをいただければ幸いです。

SELECT users.*,
  SUM(COALESCE(reviewers.value, 0)) as reviewer,
  SUM(COALESCE(communities.value,0)) as community,
  SUM(COALESCE(developers.value,0)) as developer,
  SUM(COALESCE(moderators.value,0)) as moderator,
  SUM(COALESCE(marketers.value,0)) as marketer,
  SUM(COALESCE(archivists.value,0)) as archivist,
  SUM(COALESCE(karmas.value,0)) as karma
FROM `users`
LEFT JOIN comments AS impressions
  ON impressions.user_id = users.id
  AND impressions.type = 'impression'
LEFT JOIN comments AS replies
  ON replies.user_id = users.id
  AND replies.type = 'reply'
LEFT JOIN votes AS reviewers
  ON reviewers.voteable_type = 'impression'
  AND reviewers.voteable_id = impressions.id
LEFT JOIN votes AS communities
  ON communities.voteable_type = 'reply'
  AND communities.voteable_id = replies.id
LEFT JOIN reputable_actions AS developers
  ON developers.reputation_type = 'developer'
  AND developers.user_id = users.id
LEFT JOIN reputable_actions AS moderators
  ON moderators.reputation_type = 'moderator'
  AND moderators.user_id = users.id
LEFT JOIN reputable_actions AS marketers
  ON marketers.reputation_type = 'marketer'
  AND marketers.user_id = users.id
LEFT JOIN reputable_actions AS archivists
  ON archivists.reputation_type = 'archivist'
  AND archivists.user_id = users.id
LEFT JOIN reputable_actions AS karmas
  ON karmas.reputation_type = 'karma'
  AND karmas.user_id = users.id
GROUP BY users.id
4

2 に答える 2

1

基本的に、2 つの個別のグループ化を実行し、結果を結合する必要があります。何度も参加しないようにするための秘訣があります。他の多くの投票可能なタイプまたは評判タイプがある場合は、速くならない可能性があります。

Select
  u.*,
  Coalesce(r.developer, 0) as developer,
  Coalesce(r.moderator, 0) as moderator,
  Coalesce(r.marketer, 0) as marketer,
  Coalesce(r.archivist, 0) as archivist,
  Coalesce(r.karma, 0) as karma,
  Coalesce(v.impressions, 0) as impressions,
  Coalesce(v.replies, 0) as replies
From
  users u
    Left Outer Join (
    Select
      user_id,
      Sum(Case When reputation_type = 'developer' Then value Else 0 End) as developer,
      Sum(Case When reputation_type = 'moderator' Then value Else 0 End) as moderator,
      Sum(Case When reputation_type = 'marketer' Then value Else 0 End) as marketer,
      Sum(Case When reputation_type = 'archivist' Then value Else 0 End) as archivist,
      Sum(Case When reputation_type = 'karma' Then value Else 0 End) as karma
    From
      reputable_actions
    Group By
      user_id
  ) r On u.id = r.user_id
    Left Outer Join (
    Select
      c.user_id,
      Sum(Case When c.type = 'impression' Then v.value Else 0 End) as impressions,
      Sum(Case When c.type = 'reply' Then v.value Else 0 End) as replies
    From
      comments c
        inner join -- maybe left outer?
      votes v
        on v.voteable_type = c.type And v.voteable_id = c.id
    Group By
      user_id
  ) v On u.id = v.user_id

例 (データなし) . テーブルの構造がこれと異なる場合は、お知らせください。

于 2012-12-01T00:42:29.823 に答える
1

結合の「残り」の1 つの行に一致するand/orに複数の行があります。これにより、結果の行が「乗算」され、他の集計関数の結果が乗算されます (既に述べたように)。commentsvotes

最も簡単な解決策は、別のクエリでSUM(reviewers.value)andを取得することです。SUM(communities.value)

ところで、同じ行に一致するreputable_actions(同じ の) 複数の行がある場合、同じ問題が発生します。reputation_typeusers

于 2012-12-01T00:45:50.233 に答える