2010-05-04 84 views
1

我需要計算給定表中所有記錄的單詞列表的出現次數。如果我只用了1個字,我可以這樣做:SQL Server聯合選擇從單詞列表動態構建

select count(id) as NumRecs where essay like '%word%' 

但我的名單可能是數百或數千字的,我不希望創建連續的SQL請求的數百或數千;這似乎很愚蠢。我有一種想法,我可能會創建一個存儲過程,它將接受以逗號分隔的單詞列表,並且對於每個單詞,它將運行上述查詢,然後將它們聯合在一起,並返回一個巨大的數據集。 (聽起來很合理的,正確的,但我不知道從哪裏開始這種做法...?)

短的與工會一些奇怪的事情,我可能會嘗試做一些與臨時表 - 插入一行每個單詞和記錄計數,然後從該臨時表中返回select *

如果這是可能的工會,怎麼樣?另一種方法是否有優勢(性能或其他)?

回答

5

如果你想運行多個單詞返回結果行的每個字,那麼你可以存儲這些話在一個表中,你提出的查詢,並與它一起,而不是在一個循環中運行很多查詢的查詢。請注意,這裏的關鍵詞是連接,而不是聯合。

SELECT word, COUNT(*) 
FROM words 
LEFT JOIN essays 
ON essay LIKE '%' + words.word + '%' 
GROUP BY word 

結果:

'bar', 2 
'baz', 2 
'corge', 0 
'foo', 1 
'qux', 1 

你可以看看full text search。它的運行速度比LIKE '%word%'快得多。它也將正確處理單詞邊界。基於LIKE的解決方案沒有。


測試數據:

CREATE TABLE essays (essay NVARCHAR(100) NOT NULL); 
INSERT INTO essays (essay) VALUES 
('foo bar'), 
('bar baz'), 
('baz qux'); 

DROP TABLE words; 
CREATE TABLE words (word NVARCHAR(100) NOT NULL); 
INSERT INTO words (word) VALUES 
('foo'), 
('bar'), 
('baz'), 
('qux'), 
('corge'); 
+2

也是其值得一提的是SQL Server Express的2008 R2與高級服務(免費)包括全文搜索 - 以防萬一Express Edition目前是您不使用全文搜索的限制。 – cfeduke 2010-05-04 20:50:28

+0

@cfeduke感謝您的額外細節。這個特定的應用程序正在使用MSSQL 2005企業版,所以不用擔心什麼是或不包括在內。 @Mark Byers這看起來最有前途,所以今天我會玩。 – 2010-05-05 14:19:10

+0

所以這工作得很好,在我想出瞭如何用全文搜索做到這一點之後 - 除了遺漏了我知道頻繁出現的單詞。我相信這是因爲噪音詞的刪除(它刪除的詞的例子:A,I,Have,Did)......但是我想**保留它們!它們對我們正在進行的研究很重要。有任何想法嗎? – 2010-05-07 14:56:52

0

的方法有很多在SQL Server中拆分字符串。本文介紹了幾乎每一個方法的優點和缺點:"Arrays and Lists in SQL Server 2005 and Beyond, When Table Value Parameters Do Not Cut it" by Erland Sommarskog

I prefer the number table approach to split a string in TSQL,此方法的工作,你需要做的這一個時間表設置:

SELECT TOP 10000 IDENTITY(int,1,1) AS Number 
    INTO Numbers 
    FROM sys.objects s1 
    CROSS JOIN sys.objects s2 
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number) 

一旦Numbers表格設置,創建此分割功能:

CREATE FUNCTION [dbo].[FN_ListToTable] 
(
    @SplitOn char(1)  --REQUIRED, the character to split the @List string on 
    ,@List  varchar(8000)--REQUIRED, the list to split apart 
) 
RETURNS TABLE 
AS 
RETURN 
(

    ---------------- 
    --SINGLE QUERY-- --this will not return empty rows 
    ---------------- 
    SELECT 
     ListValue 
     FROM (SELECT 
        LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(@SplitOn, List2, number+1)-number - 1))) AS ListValue 
        FROM (
          SELECT @SplitOn + @List + @SplitOn AS List2 
         ) AS dt 
         INNER JOIN Numbers n ON n.Number < LEN(dt.List2) 
        WHERE SUBSTRING(List2, number, 1) = @SplitOn 
      ) dt2 
     WHERE ListValue IS NOT NULL AND ListValue!='' 

); 
GO 

您現在可以輕鬆地拆分CSV字符串轉換成表格,並加入就可以了:

select * from dbo.FN_ListToTable(',','1,2,3,,,4,5,6777,,,') 

OUTPUT:

ListValue 
----------------------- 
1 
2 
3 
4 
5 
6777 

(6 row(s) affected) 

你現在可以加入到您的CSV像分割:

DECLARE @YourTable table (RowID int, RowValue varchar(200)) 
INSERT INTO @YourTable VALUES (1,'aaa bbb ccc ddd eee fff ggg hhh') 
INSERT INTO @YourTable VALUES (2,'bbb ddd fff hhh') 
INSERT INTO @YourTable VALUES (3,'aaa bbb zzz') 

DECLARE @Words varchar(500) 
SET @Words='aaa,bbb,ccc,zzz' 

SELECT 
    COUNT(y.RowID) AS CountOF,l.ListValue 
    FROM @YourTable         y 
     INNER JOIN dbo.FN_ListToTable(',',@Words) AS l ON y.RowValue LIKE '%'+l.ListValue+'%' 
    GROUP BY l.ListValue 

OUTPUT:

CountOF  ListValue 
----------- --------------- 
2   aaa 
3   bbb 
1   ccc 
1   zzz 

(4 row(s) affected)