初学者SQL问题:在Stack Exchange Data Explorer中查询金银标签

初学者SQL问题:在Stack Exchange Data Explorer中查询金银标签,sql,analytic-functions,Sql,Analytic Functions,我正在使用来学习SQL,但我认为这个问题的基本原理适用于其他数据库 我试图查询徽章表,根据Stexdex(从现在起我将称其为)该表具有以下模式: 徽章 身份证 用户ID 名字 日期 这适用于具有唯一名称的徽章,如[Epic]和[Legendary],但银牌和金牌专用徽章似乎因具有相同的确切名称而混合在一起 下面是我为[mysql]标记编写的一个查询示例: SELECT UserId as [User Link], Date FROM Badges Where Name =

我正在使用来学习SQL,但我认为这个问题的基本原理适用于其他数据库

我试图查询
徽章
表,根据Stexdex(从现在起我将称其为)该表具有以下模式:

  • 徽章
    • 身份证
    • 用户ID
    • 名字
    • 日期
这适用于具有唯一名称的徽章,如
[Epic]
[Legendary]
,但银牌和金牌专用徽章似乎因具有相同的确切名称而混合在一起

下面是我为
[mysql]
标记编写的一个查询示例:

SELECT
  UserId as [User Link],
  Date
FROM
  Badges
Where
  Name = 'mysql'
Order By
  Date ASC
(略加注释)输出为:

这与本文撰写之时的当前用户和收入者列表一致,但更永恒的说法是,截至2010年5月底,只有2名用户获得了金牌
[mysql]
标签:Quassnoi和Bill Karwin,上述结果表明,他们的名字是唯一出现两次的

这就是我对它的理解:

  • Id
    第一次出现(按时间顺序)是指银徽章
  • 第二次是为了黄金
现在,上面的结果将白银和黄金条目混合在一起。我的问题是:

  • 这是一个典型的设计,还是有更友好的模式/规范化/不管你怎么称呼它
  • 在当前的设计中,您将如何分别查询银徽章和金徽章?
    • 按Id分组
      并根据
      日期
      选择最小/最大值或第一/秒
    • 如何编写一个查询,首先列出所有的银徽章,然后再列出所有的金徽章?
      • 再想象一下,“真实”查询可能更复杂,即不只是按日期列出
      • 您将如何编写它,以使白银子查询和黄金子查询之间不会有太多重复
    • 用两个完全不同的查询来代替是不是更为典型
    • 这个成语叫什么?一个行“分区”查询,将它们放入“bucket”还是什么

需求澄清 最初,我需要以下输出,基本上是:

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     // :
但是到目前为止,关于白银和黄金的单独专栏给出的答案也很好,所以也可以从这个角度进行探讨。不过,我还是很好奇你会怎么做

这是一个典型的设计,还是有更友好的模式/规范化/不管你怎么称呼它

当然,您可以添加类型代码以使其更显式。但是当你认为不能在银币前拿到一枚金质徽章时,日期戳对区分它们有很大的意义。 在当前的设计中,您将如何分别查询银徽章和金徽章?按Id分组并按日期选择最小/最大值或第一/第二

是-加入一个派生表(也称为内联视图),该表是一个用户列表&最短日期将返回银徽章。使用计数(*)大于等于1的
也可以。您必须使用GROUP BY和COUNT(*)=2`组合才能获得金徽章-最大日期不能确保一个用户ID有多个记录

如何编写一个查询,首先列出所有的银徽章,然后再列出所有的金徽章

抱歉-由用户,或所有的银牌先,然后金牌?前者可以简单地通过使用t.userid、t.date
进行排序;后者我可能会使用分析函数(即:ROW_NUMBER(),RANK())

用两个完全不同的查询来代替是不是更为典型

看看上面关于你的要求有多模糊,对我来说无论如何

这个成语叫什么?一个行“分区”查询,将它们放入“bucket”还是什么


你所问的是以下同义词:分析、窗口、排名……

你可以这样做,只依赖于聚合中的日期或计数

可以说,先查询白银再查询黄金也毫无意义,而是像这样并排获取数据:

不幸的是,您还没有真正指定您想要什么,但是聚合的一个好的起点是用简单的英语表达它

示例:“为每个用户提供标记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:它是两个独立的记录集。分离器是不可使用的。作为基于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

更进一步:这不属于meta!这真是一个SQL问题+1.很好的方法,银和金作为不同的列!这比我想的要好得多(即重新排列行)。
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