根据单个表中的关键字选择相关文章

时间:2013-01-23 05:59:07

标签: asp.net sql-server sql-server-2008 tsql

我正在制作一个网页项目,其中显示其中一个页面的文章详情,另外我还需要根据keywordstags显示前5个相关文章。

我不确定如何使用T-SQL完全做到这一点,而不是从后面的代码中进行部分处理。

我使用FUNCTION来分割我的关键字并将结果传递给其他查询以获得对我不起作用的所需结果。

CREATE TABLE Article
(
 ArticleID int,
 Title varchar(200),
 Description varchar(500),
 Details nvarchar(MAX),
 keywords varchar(100)
 )

INSERT INTO Article VALUES(1, 'Article One','Article desc', 'article details', 'one,two,three')
INSERT INTO Article VALUES(2, 'Article Two','Article desc', 'article details', 'two,three,four')
INSERT INTO Article VALUES(3, 'Article three','Article desc', 'article details', 'three,four,five')
INSERT INTO Article VALUES(4, 'Article four','Article desc', 'article details', ',four,five,six')
INSERT INTO Article VALUES(5, 'Article five','Article desc', 'article details', 'two,three')
INSERT INTO Article VALUES(6, 'Article six','Article desc', 'article details', 'eight, nine')
INSERT INTO Article VALUES(7, 'Article six','Article desc', 'article details', 'ten, nine')
INSERT INTO Article VALUES(8, 'Article six','Article desc', 'article details', 'eleven, eight')

功能

CREATE FUNCTION [dbo].[uf_SplitKeywords] 
   (  @DELIMITER VARCHAR(5), 
      @LIST      VARCHAR(MAX) 
   ) 
   RETURNS @TABLEOFVALUES TABLE 
      (  ROWID   SMALLINT IDENTITY(1,1), 
         [VALUE] VARCHAR(MAX) 
      ) 
AS 
   BEGIN

      DECLARE @LENSTRING INT 

      WHILE LEN( @LIST ) > 0 
         BEGIN 

            SELECT @LENSTRING = 
               (CASE CHARINDEX( @DELIMITER, @LIST ) 
                   WHEN 0 THEN LEN( @LIST ) 
                   ELSE ( CHARINDEX( @DELIMITER, @LIST ) -1 )
                END
               ) 

            INSERT INTO @TABLEOFVALUES 
               SELECT SUBSTRING( @LIST, 1, @LENSTRING )

            SELECT @LIST = 
               (CASE ( LEN( @LIST ) - @LENSTRING ) 
                   WHEN 0 THEN '' 
                   ELSE RIGHT( @LIST, LEN( @LIST ) - @LENSTRING - 1 ) 
                END
               ) 
         END

      RETURN 

   END

我需要什么?

显示ID为3的文章

SELECT ArticleID, Title, Keywords FROM Article WHERE ArticleID = 3

然后我需要根据关键字three,four,five显示相关文章 从本案例中选择的文章应该是articleid=3的文章  在这种情况下,结果应该显示id为1,2,3,4,5的文章,因为关键字只与这些行匹配。

我正在尝试通过以下查询来实现此目的

SELECT TOP 5 ArticleID, Title, Keywords FROM Articles WHERE Keywords IN
(SELECT '''%'+ VALUE+ '%''' AS VALUE FROM [uf_SplitKeywords] (',', 'one,two,three'))

我很感激这方面的帮助。

sqlFiddle上的示例由于某种原因,我无法创建上面在sqlFiddle上提到的FUNCTION。

2 个答案:

答案 0 :(得分:1)

Alter FUNCTION [dbo].[uf_SplitKeywords] 
   (  @DELIMITER VARCHAR(5), 
      @LIST      VARCHAR(MAX) 
   ) 
   RETURNS @TABLEOFVALUES TABLE 
      (  ROWID   int IDENTITY(1,1), 
         [VALUE] VARCHAR(MAX) 
      ) 
AS 
   BEGIN
   Declare @Pos int
   While LEN(@List) > 0
      begin
        Select @Pos=CHARINDEX(@Delimiter,@List,1)      
        if @Pos>0
           begin
             Insert into @TABLEOFVALUES ([Value]) Values (SubString(@List,1,@Pos -1))
             Select @LIST = STUFF(@List,1,@Pos ,'')
           end
        else  
            begin
            Insert into @TABLEOFVALUES ([Value]) Values (@List)
            Select @LIST =''
            end  
      end
   Return 
   End

通过

打电话
Select Distinct b.ArticleID,b.Title,b.Description,b.Details,b.KeyWords from
(
Select * from Article a1 
CROSS APPLY [dbo].[uf_SplitKeywords](',',keywords) f1
Where a1.ArticleID=3
) a
Join
(
Select * from Article a2 
CROSS APPLY [dbo].[uf_SplitKeywords](',',keywords) f2
) b
on a.Value=b.Value

答案 1 :(得分:1)

如果我理解正确,您的文章中包含“关键字”和“代码”。您希望使用相同的“关键字”或“代码”显示相关文章。

从概念上讲,您需要修改数据库表的设计。您可以创建新表Article_Keywords,而不是在Article表中插入关键字作为varchar(100) 使用ArticleID int作为外键约束,将另一列作为varchar。

然后,您可以根据文章ID加入表格。所以Article_Keywords看起来像:

最佳实践解决方案

不允许ID列上的空值

alter TABLE Article
alter column ArticleID int not null

将主键添加到ID列以进行索引和与其他表联接

alter TABLE Article
add constraint PK_ArticleID PRIMARY KEY (ArticleID)

创建新表文章关键字

create table Article_Keywords
(
    [ArticleID] int not null,
    [Keywords] nvarchar(100),
    Foreign key ([ArticleID]) References Article(ArticleID),
)

INSERT数据

insert into [Article_Keywords] Values (1,'one'),(1,'two'),(1,'three');
insert into [Article_Keywords] Values (2,'two'),(2,'three'),(2,'four');
insert into [Article_Keywords] Values (3,'three'),(3,'four'),(3,'five');
insert into [Article_Keywords] Values (4,'four'),(4,'five'),(4,'six'),(5,'two'),(5,'three'),(6,'eight'),(6,'nine'),(7,'nine'),(7,'ten'),(8,'eleven');

delete from Article_Keywords where [ArticleID] = [Keywords]

SELECT
    DISTINCT AK1.ArticleID
FROM Article_Keywords AK1
WHERE EXISTS (
SELECT AK2.Keywords from Article_Keywords AK2
WHERE AK2.[ArticleID] = 3 AND AK1.[KEYWORDS] = AK2.[KEYWORDS]
) 

但是,如果您觉得需要沿着前进的方向前进,可以使用游标(不可取):

创建一个临时表来存储所有相关文章

IF ( OBJECT_ID('tempdb.dbo.#RelatedArticles') IS NOT NULL ) DROP TABLE #RelatedArticles
CREATE TABLE #RelatedArticles (
    ArticleID int
);


DECLARE @VALUE NVARCHAR(100)
DECLARE Keyword_Cursor Cursor For

使用[uf_SplitKeywords]从Article表

中提取关键字
SELECT [Value] FROM [uf_SplitKeywords] (',',(SELECT [KEYWORDS] FROM ARTICLE WHERE ARTICLEID = 3))

OPEN Keyword_Cursor

FETCH NEXT FROM Keyword_Cursor into @VALUE

WHILE @@FETCH_STATUS = 0
BEGIN

    insert into #RelatedArticles
    SELECT [ArticleID] from Article
    where [keywords] like (SELECT '%' + @VALUE +  '%');

    FETCH NEXT FROM Keyword_Cursor into @VALUE
END

CLOSE Keyword_Cursor
DEALLOCATE Keyword_Cursor

SELECT DISTINCT ArticleID from #RelatedArticles

比较这两种方法,您会发现在设计复杂项目时,拥有更好的数据库设计将为您节省更多时间。