2009-05-19 3 views
3

J'ai une table qui répertorie une entrée de texte freet d'une enquête où enterents ont été autorisés à entrer dans leurs réponses (en ce qui concerne les couleurs qu'ils aimeraient avoir dans leur mariage)fonction serveur Sql pour afficher la fréquence des mots dans une colonne

Je voudrais écrire une fonction sql qui rassemble toutes les informations de cette colonne, et les ordres compte la fréquence de chaque mot, en ordonnant le jeu de résultats par ce compte.

Response 
-------- 
Red and White 
green 
White and blue 
Blue 
Dark blue 

Je voudrais que le tableau ci-dessus à commander comme suit

Response Frequency 
-------- --------- 
Blue  3 
White  2 
And  2 
Red  1 
Green  1 

Je peux dépouiller tous les mots d'ordures comme « et » après que la fonction est exécutée. Est-ce que quelqu'un connaît de bonnes fonctions qui produisent ce comportement?

Répondre

4

Ok, cela fonctionne un régal. Tout d'abord une fonction de séparer les valeurs ...

Alter Function dbo.SeparateValues  

( 
@data VARCHAR(MAX),  
@delimiter VARCHAR(10)  
)  
RETURNS  
@tbldata TABLE(col VARCHAR(MAX))  
As  
--Declare @data VARCHAR(MAX) ,@delimiter VARCHAR(10)  
--Declare @tbldata TABLE(col VARCHAR(10))  
--Set @data = 'hello,how,are,you?,234234'  
--Set @delimiter = ','  
--DECLARE @tbl TABLE(col VARCHAR(10))  
Begin  
DECLARE @pos INT  
DECLARE @prevpos INT  
SET @pos = 1  
SET @prevpos = 0  

WHILE @pos > 0  
BEGIN  
SET @pos = CHARINDEX(@delimiter, @data, @prevpos+1)  
if @pos > 0  
INSERT INTO @tbldata(col) VALUES(LTRIM(RTRIM(SUBSTRING(@data, @prevpos+1, @[email protected]))))  
else  
INSERT INTO @tbldata(col) VALUES(LTRIM(RTRIM(SUBSTRING(@data, @prevpos+1, len(@data)[email protected]))))  
SET @prevpos = @pos  
End  

RETURN  
END  

j'applique juste à ma table ...

Select Count(*), sep.Col FROM (
     Select * FROM (
      Select value = Upper(RTrim(LTrim(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(response, ',', ' '), '.', ' '), '!', ' '), '+', ' '), ':', ' '), '-', ' '), ';', ' '), '(', ' '), ')', ' '), '/', ' '), '&', ''), '?', ' '), ' ', ' '), ' ', ' ')))) FROM Responses 
     ) easyValues 
     Where value <> '' 
    ) actualValues 
    Cross Apply dbo.SeparateValues(value, ' ') sep 
    Group By sep.Col 
    Order By Count(*) Desc 

Ok, alors je suis allé OTT avec mes tables imbriquées, mais je l'ai dépouillé tous les caractères de la merde, séparé les valeurs et gardé un total cumulé des mots les plus fréquemment utilisés.

+0

La performance de ceci est probablement terrible avec les nombreuses opérations de remplacement et la fonction SeparateValues ​​très lente. Essayez d'utiliser quelque chose comme ça pour le fractionnement de la chaîne au moins: http://sqlblog.com/blogs/adam_machanic/archive/2009/04/28/sqlclr-string-splitting-part-2-even-faster-even-more- scalable.aspx – devinbost

1

Vous êtes le problème principal est que vous manquez une fonction de division dans SQL Server.

Theres un échantillon d'un ici qui semble assez bon ..

http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=50648

En utilisant, vous écrivez un proc stocké le long des lignes de ...

CREATE TABLE #Temp (Response nvarchar(50), Frequency int) 

DECLARE @response nvarchar(100) 
DECLARE db_cursor CURSOR FOR 
SELECT response FROM YourTable 

OPEN db_cursor 
FETCH NEXT FROM db_cursor INTO @response 

WHILE @@FETCH_STATUS = 0 
BEGIN 
     /* Pseudo Code */ 
     --Split @Response 
     --Iterate through each word in returned list 
     --IF(EXISTS in #TEMP) 
     -- UPDATE THAT ROW & INCREMENT THE FREQUENCY 
     --ELSE 
     -- NEW WORD, INSERT TO #Temp WITH A FREQUENCY OF 1 

     FETCH NEXT FROM db_cursor INTO @response 
END 

SELECT * FROM #Temp 

Theres probablement moins fugly façon de le faire sans curseurs, mais si c'est juste quelque chose que vous devez exécuter une fois, et vous êtes table ou réponses n'est pas phénoménalement grande, alors cela devrait fonctionner

+0

Merci - Je aurais dû mentionner - je refuse cursours, je vais chercher à le rendre CTE! – digiguru

+0

Si vous êtes sur SQL 2005 ou 2008, vous pouvez également envisager d'écrire ceci comme une fonction CLR dans .NET, le spliting/itération/comptage serait probablement beaucoup plus facile dans un langage .NET –

0
DECLARE @phrases TABLE (id int, phrase varchar(max)) 
INSERT @phrases values 
(1,'Red and White' ), 
(2,'green'   ), 
(3,'White and blue'), 
(4,'Blue'   ), 
(5,'Dark blue'  ); 

SELECT word, COUNT(*) c 
FROM @phrases 
CROSS APPLY (SELECT CAST('<a>'+REPLACE(phrase,' ','</a><a>')+'</a>' AS xml) xml1) t1 
CROSS APPLY (SELECT n.value('.','varchar(max)') AS word FROM xml1.nodes('a') x(n)) t2 
GROUP BY word 
word   freq 
----------- ----------- 
and   2 
blue  3 
Dark  1 
green  1 
Red   1 
White  2 
Questions connexes