2013-04-29 1 views
1

У меня необычная ситуация. Пожалуйста, обратите внимание на следующий код:Процент значений для Топ 3 из поля символов

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

Я хотел бы запрос, который дает мне строку символов, как это: А (16%), B (12%), C (8%)

Пожалуйста обратите внимание на следующее:

  • Я не хочу иметь пустые строки, строки с пробелами или нулями, перечисленных в топ-3, но я хочу, процент значений рассчитывается с использованием всего количества записей для таблицы ,
  • Связи могут быть проигнорированы, поэтому, если в списке было 22 значения с частотой 8%, все в порядке, чтобы просто вернуть то, что было первым.
  • Проценты могут быть округлены до целых чисел.

Я хотел бы найти самый простой способ написать этот запрос, сохраняя при этом совместимость T-SQL с SQL Server 2005. Каков наилучший способ сделать это? Функции окна?

ответ

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 
+1

Нет переменных и волос быстрее, чем у меня на моей коробке ... приятно –

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 
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) колонке, однако.