1

I have an unusual situation. Please consider the following code:

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)
      , ('');

I would like a query which gives me a character string like this: A (16%), B (12%), C(8%)

Please notice the following:

  • I don't want to have empty strings, strings with all blanks, or nulls listed in the top 3, but I do want the percentage of values calculated using the entire record count for the table.
  • Ties can be ignored, so if there were 22 values in the list with 8% frequency, it's alright to simply return whichever one is first.
  • Percentages can be rounded to whole numbers.

I'd like to find the easiest way to write this query while still retaining T-SQL compatibility back to SQL Server 2005. What is the best way to do this? Window Functions?

4

3 回答 3

2

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

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)列中。

于 2013-04-29T20:48:46.013 回答
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
于 2013-04-29T20:23:01.737 回答
2

我会去的。

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 
于 2013-04-29T20:50:24.903 回答