3

Stack Exchange Data Explorerを使用してSQLを学習していますが、質問の基本は他のデータベースにも当てはまると思います。

私はBadgesテーブルをクエリしようとしています。Stexdexによると(これからこれを呼び出します)、次のスキーマがあります。

  • バッジ
    • Id
    • ユーザーID
    • 名前
    • 日にち

[Epic]これは、のような一意の名前のバッジには適しています[Legendary]が、シルバーとゴールドのタグ固有のバッジは、まったく同じ名前を持つことで混ざり合っているようです。

[mysql]これが私がタグのために書いたクエリの例です:

SELECT
  UserId as [User Link],
  Date
FROM
  Badges
Where
  Name = 'mysql'
Order By
  Date ASC

(わずかに注釈が付けられた)出力は次のとおりです。stexdexで見られるように

User Link       Date                    
--------------- -------------------     // all for silver except where noted
Bill Karwin     2009-02-20 11:00:25     
Quassnoi        2009-06-01 10:00:16     
Greg            2009-10-22 10:00:25     
Quassnoi        2009-10-31 10:00:24     // for gold
Bill Karwin     2009-11-23 11:00:30     // for gold
cletus          2010-01-01 11:00:23    
OMG Ponies      2010-01-03 11:00:48     
Pascal MARTIN   2010-02-17 11:00:29 
Mark Byers      2010-04-07 10:00:35     
Daniel Vassallo 2010-05-14 10:00:38 

これは、この記事の執筆時点でのシルバーゴールドの獲得者の現在のリストと一致していますが、より時代を超越した言葉で言えば、2010年5月末現在、ゴールド[mysql]タグを獲得しているのはQuassnoiとBillKarwinの2人だけです。上記の結果では、2回表示されるのは名前だけです。

だからこれは私がそれを理解する方法です:

  • 初めてId登場するのは(時系列で)シルバーバッジ用です
  • 二度目は金のためです

さて、上記の結果はシルバーとゴールドのエントリーを混ぜ合わせています。私の質問は次のとおりです。

  • これは典型的な設計ですか、それとももっとフレンドリーなスキーマ/正規化/あなたがそれを呼んでいるものは何ですか?
  • 現在のデザインでは、シルバーバッジとゴールドバッジを別々にクエリする方法を教えてください。
    • GROUP BY IdDateどういうわけかで最小/最大または最初/秒を選ぶ?
    • 最初にすべてのシルバーバッジをリストし、次にすべてのゴールドバッジをリストするクエリをどのように作成できますか?
      • また、「実際の」クエリは、日付ごとにリストするだけでなく、より複雑になる可能性があることも想像してみてください。
      • シルバーとゴールドのサブクエリの間で繰り返しが多すぎないように、どのように記述しますか?
    • 代わりに、2つの完全に別個のクエリを実行する方がおそらくより一般的ですか?
    • このイディオムは何と呼ばれていますか?それらを「バケット」か何かに入れるための行の「パーティション化」クエリ?

要件の明確化

もともと私は次の出力が欲しかったのですが、本質的には:

User Link       Date                    
--------------- -------------------     
Bill Karwin     2009-02-20 11:00:25     // result of query for silver
Quassnoi        2009-06-01 10:00:16     // :
Greg            2009-10-22 10:00:25     // :
cletus          2010-01-01 11:00:23     // :
OMG Ponies      2010-01-03 11:00:48     // :
Pascal MARTIN   2010-02-17 11:00:29     // :
Mark Byers      2010-04-07 10:00:35     // :
Daniel Vassallo 2010-05-14 10:00:38     // :
------- maybe some sort of row separator here? can SQL do this? -------
Quassnoi        2009-10-31 10:00:24     // result of query for gold
Bill Karwin     2009-11-23 11:00:30     // :

しかし、これまでのところ、シルバーとゴールドの列が分かれているという答えも素晴らしいので、その角度も自由に追求してください。しかし、私はあなたが上記をどのように行うのかまだ興味があります。

4

2 に答える 2

4

これは典型的な設計ですか、それとももっとフレンドリーなスキーマ/正規化/あなたがそれを呼んでいるものは何ですか?

もちろん、タイプコードを追加して、より明確にすることができます。しかし、銀のバッジの前に金のバッジを取得できないことを考えると、日付スタンプはそれらを区別するのに非常に理にかなっています。

現在のデザインでは、シルバーバッジとゴールドバッジを別々にクエリする方法を教えてください。GROUP BY Idを使用して、日付で最小/最大または最初/秒を選択しますか?

はい-ユーザーのリストである派生テーブル(別名インラインビュー)に参加すると、最小の日付でシルバーバッジが返されます。使用HAVING COUNT(*) >= 1も機能します。ゴールドバッジを取得するには、GROUPBYとHAVINGCOUNT(*)= 2`の組み合わせを使用する必要があります。最大日付では、ユーザーIDに複数のレコードがあることは保証されません...

最初にすべてのシルバーバッジをリストし、次にすべてのゴールドバッジをリストするクエリをどのように作成できますか?

申し訳ありませんが、ユーザーによるものですか、それとも最初にすべてのシルバー、次にゴールドですか?前者は、ORDER BY t.userid, t.date;を使用するだけで実行できます。後者の場合、分析関数(IE:ROW_NUMBER()、RANK())を使用する可能性があります。

代わりに、2つの完全に別個のクエリを実行する方がおそらくより一般的ですか?

とにかく、あなたの要件がどれほど曖昧であるかについては、上記を参照してください...

このイディオムは何と呼ばれていますか?それらを「バケット」か何かに入れるための行の「パーティション化」クエリ?

あなたが質問していることは、次の同義語によって参照されます:分析、ウィンドウ処理、ランキング...

于 2010-06-06T18:59:21.983 に答える
3

あなたはこのようなことをし、日付または集計のカウントのみに依存します。

間違いなく、シルバーの後にゴールドをクエリすることも意味がありませんが、次のようにデータを並べて取得します。

残念ながら、あなたは本当にあなたが望むものを指定していませんが、集合体の良い出発点はそれを平易な英語で表現することです

例:「タグmysqlのユーザーごとのシルバーおよびゴールドバッジアワードの日付を教えてください」。これは何をしますか:

SELECT
  UserId as [User Link],
  min(Date) as [Silver Date],
  case when count(*) = 1 THEN NULL ELSE max(date) END
FROM
  Badges
Where
  Name = 'mysql'
group by
  UserId
Order By
  case when count(*) = 1 THEN NULL ELSE max(date) END DESC, min(Date)

更新後の編集:

必要な出力は実際にはSQLではありません。2つの別々のレコードセットです。セパレーターは使用できません。setbベースの操作として、「自然な」順序がないため、次の順序が導入されます。

SELECT
  UserId as [User Link],
  min(Date) as [Date],
  0 as dummyorder
FROM
  Badges
Where
  Name = 'mysql'
group by
  UserId
union all
select
  UserId as [User Link],
  max(Date) as [Date],
  1 as dummyorder
FROM
  Badges
Where
  Name = 'mysql'
group by
  UserId
having
  count(*) = 2
Order By
  dummyorder, Date
于 2010-06-06T19:05:31.767 に答える