【问题标题】:Percentage of Values for Top 3 from a Character Field字符字段中前 3 个值的百分比
【发布时间】:2013-04-29 20:17:24
【问题描述】:

我有一个不寻常的情况。请考虑以下代码:

IF OBJECT_ID('tempdb..#CharacterTest') IS NOT NULL
    DROP TABLE #CharacterTest

CREATE TABLE #CharacterTest
(
  [ID] int IDENTITY(1, 1) NOT NULL,
[CharField] varchar(50) NULL 
)


INSERT INTO #CharacterTest (CharField)
VALUES  ('A')
      , ('A')
      , ('A')
      , ('A')
      , ('B')
      , ('B')
      , ('B')
      , ('C')
      , ('C')
      , ('D')
      , ('D')
      , ('F')
      , ('G')
      , ('H')
      , ('I')
      , ('J')
      , ('K')
      , ('L')
      , ('M')
      , ('N')
      , (' ')
      , (' ')
      , (' ')
      , (NULL)
      , ('');

我想要一个查询,它给我一个这样的字符串: A (16%), B (12%), C(8%)

请注意以下几点:

  • 我不希望在前 3 名中列出空字符串、全为空格的字符串或空值,但我确实希望使用表的整个记录​​计数来计算值的百分比。
  • 可以忽略平局,因此如果列表中有 22 个频率为 8% 的值,则可以简单地返回第一个出现的值。
  • 百分比可以四舍五入为整数。

我想找到编写此查询的最简单方法,同时仍保持与 SQL Server 2005 的 T-SQL 兼容性。最好的方法是什么?窗口函数?

【问题讨论】:

    标签: tsql sql-server-2005 window-functions


    【解决方案1】:

    我会去的。

    WITH T1
         AS (SELECT [CharField],
                    100.0 * COUNT(*) OVER (PARTITION BY [CharField]) / 
                                                 COUNT(*) OVER () AS Pct
             FROM   #CharacterTest),
         T2
         AS (SELECT DISTINCT TOP 3 *
             FROM   T1
             WHERE  [CharField] <> '' --Excludes all blank or NULL as well
             ORDER  BY Pct DESC)
    SELECT STUFF((SELECT ',' + [CharField] + ' (' + CAST(CAST(ROUND(Pct,1) AS INT) AS VARCHAR(3)) + ')'
                  FROM   T2
                  ORDER BY Pct DESC
                  FOR XML PATH('')), 1, 1, '') AS Result 
    

    【讨论】:

    • 没有变量,而且我的盒子上的头发比我的快...不错
    【解决方案2】:

    我的第一次尝试可能是这样。并不是说这是最好的处理方式,而是说它会起作用。

    DECLARE @TotalCount INT
    SELECT @TotalCount = COUNT(*) FROM #CharacterTest AS ct
    
    SELECT TOP(3) CharField, COUNT(*) * 1.0 / @TotalCount AS OverallPercentage
    FROM #CharacterTest AS ct
    WHERE CharField IS NOT NULL AND REPLACE(CharField, ' ', '') <> ''
    GROUP BY CharField
    ORDER BY COUNT(*) desc
    
    DROP TABLE #CharacterTest
    

    【讨论】:

      【解决方案3】:

      这应该得到你需要的字符串:

      declare @output varchar(200);
      
      with cte as (
          select CharField
              , (count(*) * 100) / (select count(*) from #CharacterTest) as CharPct
              , row_number() over (order by count(*) desc, CharField) as RowNum
          from #CharacterTest
          where replace(CharField, ' ', '') not like ''
          group by CharField
      )
      select @output = coalesce(@output + ', ', '') + CharField + ' (' + cast(CharPct as varchar(11)) + '%)'
      from cte
      where RowNum <= 3
      order by RowNum;
      
      select @output;
      
      -- Returns:
      -- A (16%), B (12%), C (8%)
      

      不过,我会提请注意将单个字符存储在 varchar(50) 列中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-23
        相关资源
        最近更新 更多