【问题标题】:SQL Query to display records categorically用于分类显示记录的 SQL 查询
【发布时间】:2016-01-11 13:17:11
【问题描述】:

我的查询显示如下所示的输出

`UserName   Status   Count`  
`A          Pass      32`
`A          fail      2`
`A          Hold      4`
`B          Fail      12`
`C          Pass      40`
`C          Fail      4`
`C          Hold      3`
`D          Pass      2`

我想要显示输出,首先记录为用户名 C 及其详细信息,第二个记录为 A 及其详细信息。我正在尝试获取具有高通状态的前 5 名记录及其相关的用户名记录。如果该用户名存在于前 5 名中,我不想留下第 6 条记录。请帮助

抱歉,我无法格式化为表格格式。

【问题讨论】:

  • “表格数据”是 RDBMS 吗?如果没有,您使用的是哪个品牌的 SQL?
  • 你能提供你需要的样本输出吗?您只需要显示 status = 'pass" 的记录?
  • 另外,您使用的表结构也会有所帮助。
  • 我使用 SQL 2012 。上面提供的表格数据是我的查询的输出。
  • OUTPUT 应该是,前 5 条记录和最大数量的 C 为 Pass 状态,应首先显示,与 UserName 'C' 相关的其他记录应紧随其后。在那之后用户名'A'和它的记录。由于我们检索到 Top 5 ,我不想错过 UserName 'A' last record ,因为在选择 Top 5 时它将被忽略。

标签: sql sql-server sql-server-2012 tabular


【解决方案1】:

要实现想要的上市顺序比较简单:

select top 6 * from #tbl INNER JOIN (
  SELECT UserName u, cnt pc FROM #tbl WHERE Status='Pass'
  ) ord ON u=UserName ORDER BY pc desc,status desc

但是,如果第一个结果集不完整,将其限制为 5 行并不容易。我还在努力……

编辑

好吧,经过几次尝试后,我发现,当您将输出行数限制为某个最大数量时,取决于数据结构,如果您坚持用户的所有行数可能会少两条记录始终完整列出。因此,如果我们将输出限制为 6 行,如果下一个用户再提供 3 行,则列表可能会在第 4 行结束。接受这一点后,您可以使用以下内容:

;WITH cnts AS ( SELECT 
  UserName un,
  SUM(CASE Status 
           WHEN 'Pass' THEN 10000   --  weighing system
           WHEN 'Hold' THEN 100     --  to sort the results ...
                       ELSE 1 END * cnt) scr, -- --> score for sorting
  COUNT(*) ncnt                     --  row count per UserName
  FROM #tbl GROUP BY UserName
)
SELECT UserName,Status,cnt,scr,acnt FROM #tbl INNER JOIN (
 SELECT un,scr,(SELECT SUM(ncnt) FROM cnts WHERE scr>=c.scr) acnt 
 FROM cnts c WHERE (SELECT SUM(ncnt) FROM cnts WHERE scr>=c.scr) <=6 
) srt ON UserName=un
 ORDER BY scr DESC, UserName, Status desc

here

子查询(SELECT SUM(ncnt) FROM cnts WHERE scr&gt;=c.scr) 表示累积的行数,我在srt-子查询的where 子句中使用它来限制输出。

与我的第一种方法相反,我现在根据scr 进行内部排序,这是一个内部分数,我通过将所有通过/保持/失败计数与不同的加权因子相加来计算。如果不这样做,即使没有其他用户做得更好,也永远不会列出没有“通过”的用户。

【讨论】:

    【解决方案2】:
    ;WITH CTE_UserRanking AS (
        SELECT
            UserID,
            DENSE_RANK() OVER (ORDER BY COUNT(*) DESC) AS user_rank
        FROM
            dbo.User_Scores S
        WHERE
            S.Status = 'Pass'
        GROUP BY
            UserID
    )
    SELECT
        U.UserName,
        S.Status,
        COUNT(*)
    FROM
        CTE_UserRanking R
    INNER JOIN dbo.Users U ON U.UserID = R.UserID
    INNER JOIN dbo.Scores S ON S.UserID = R.UserID
    WHERE
        R.user_rank <= 5
    GROUP BY
        U.UserID,
        U.UserName,
        S.Status
    ORDER BY
        R.user_rank
    

    【讨论】:

    • 您从哪里获得UserID 列?这同样适用于表UsersScores ... OP 只提到了一个用作伪表的表格输出。
    • 我对他的表结构做了一些推断,因为他还没有提供任何数据。
    【解决方案3】:

    使用分析函数获取每个用户的通过率,获得前 5 名,并按通过率排序。

    select username, status, cnt
    from
    (
      select top(5) username, status, cnt, sum(case when status = 'Pass' then cnt else 0 end)
                                           over (partition by username) as passed
      from mytable
      order by 4 desc
    ) top5
    order by 
      passed desc, 
      username, 
      case status when 'Pass' then 1 when 'fail' then 2 else 3 end;
    

    (我冒昧地将您的计数列称为cnt,因为COUNT是SQL中的保留字,最好不要选择列名。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-16
      • 1970-01-01
      • 2021-02-02
      • 1970-01-01
      相关资源
      最近更新 更多