newsClass表:
------------------
id --int identity primary key
className --varchar --类别名称
=================
id className
1 国内新闻
2 国际新闻
3 本埠新闻
4 科技新闻news表:
-------------------
id  --int identity primary key
classid现在我们老板要我实现这个功能,就是一条新闻能分配多个类别。比如,一条新闻,它的类别要设为国内新闻(1)和科技新闻(4)
我想了两种方法。
一种是,news表里的classid为int,存放一个类别ID,然后重复插入该条记录。
insert into news (classid) values (1) --国内新闻
insert into news (classid) values (4) --科技新闻另一种是,news表的classid为varchar,存放类别ID的列表:
insert into news (classid) values('1,4')
以我的理解,这种方法似乎比第一种方法要好。但是,我取数据的时候怎么取?比如,我要取出news.id和newsclass.className
第一种比较好取,逐条用inner join
第二种好像不怎么好取。我想问题的是:
(1)第二种方法怎么取出满足要求的数据?
(2)是否有比我说的这两种更好的方法?

解决方案 »

  1.   

    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_splitSTR]') and xtype in (N'FN', N'IF', N'TF'))
    drop function [dbo].[f_splitSTR]
    GOif exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[tb_splitSTR]') and objectproperty(id,N'IsUserTable')=1)
    drop table [dbo].[tb_splitSTR]
    GO--3.2.3.2 使用永久性分拆辅助表法
    --字符串分拆辅助表
    SELECT TOP 8000 ID=IDENTITY(int,1,1) INTO dbo.tb_splitSTR
    FROM syscolumns a,syscolumns b
    GO--字符串分拆处理函数
    CREATE FUNCTION f_splitSTR(
    @s     varchar(8000),  --待分拆的字符串
    @split  varchar(10)     --数据分隔符
    )RETURNS TABLE
    AS
    RETURN(
    SELECT col=CAST(SUBSTRING(@s,ID,CHARINDEX(@split,@s+@split,ID)-ID) as varchar(100))
    FROM tb_splitSTR
    WHERE ID<=LEN(@s+'a') 
    AND CHARINDEX(@split,@split+@s,ID)=ID)
    GO
      

  2.   

    --示例数据
    CREATE TABLE tb(ID int,col varchar(50))
    INSERT tb SELECT 1,'1,2,3,4'
    UNION ALL SELECT 1,'1,3,4'
    UNION ALL SELECT 1,'1,4'
    UNION ALL SELECT 2,'11,3,4'
    UNION ALL SELECT 2,'1,33,4'
    UNION ALL SELECT 3,'1,3,4'
    GO--1. 字符串并集处理函数
    CREATE FUNCTION dbo.f_mergSTR(@ID int)
    RETURNS varchar(50)
    AS
    BEGIN
    DECLARE @t TABLE(ID int identity,b bit)
    --分拆处理辅助表,由于列col的最大宽度为50,所以只需要1到50的分拆辅助记录
    INSERT @t(b) SELECT TOP 50 0 
    FROM syscolumns DECLARE @r varchar(50)
    SET @r=''
    SELECT @r=@r+','+s
    FROM(
    SELECT s=SUBSTRING(a.col,b.ID,CHARINDEX(',',a.col+',',b.ID)-b.ID)
    FROM tb a,@t b
    WHERE a.ID=@ID
    AND b.ID<=LEN(a.col) 
    AND SUBSTRING(','+a.col,b.ID,1)=','
    GROUP BY SUBSTRING(a.col,b.ID,CHARINDEX(',',a.col+',',b.ID)-b.ID)
    )a ORDER BY s
    RETURN(STUFF(@r,1,1,''))
    END
    GO--调用用户定义实现交并集查询
    SELECT ID,col=dbo.f_mergSTR(ID)
    FROM tb
    GROUP BY ID
    GO
    /*================================================================*/
    --2. 字符串交集处理函数
    CREATE FUNCTION dbo.f_mergSTR(@ID int)
    RETURNS varchar(50)
    AS
    BEGIN
    DECLARE @t TABLE(ID int identity,b bit)
    --分拆处理辅助表,由于列col的最大宽度为50,所以只需要1到50的分拆辅助记录
    INSERT @t(b) SELECT TOP 50 0 
    FROM syscolumns DECLARE @r varchar(50)
    SET @r=''
    SELECT @r=@r+','+s
    FROM(
    SELECT s=SUBSTRING(a.col,b.ID,CHARINDEX(',',a.col+',',b.ID)-b.ID)
    FROM tb a,@t b
    WHERE a.ID=@ID
    AND b.ID<=LEN(a.col) 
    AND SUBSTRING(','+a.col,b.ID,1)=','
    GROUP BY SUBSTRING(a.col,b.ID,CHARINDEX(',',a.col+',',b.ID)-b.ID)
    HAVING COUNT(*)=(SELECT COUNT(*) FROM tb WHERE ID=@ID))a
    RETURN(STUFF(@r,1,1,''))
    END
    GO--调用用户定义实现交交集查询
    SELECT ID,col=dbo.f_mergStr(ID)
    FROM tb
    GROUP BY ID
    GO
      

  3.   

    --示例数据
    CREATE TABLE tb(ID int,col varchar(50),num int)
    INSERT tb SELECT 1,'aa,bb,cc',10
    UNION ALL SELECT 2,'aa,aa,bb',20
    UNION ALL SELECT 3,'aa,aa,bb',20
    UNION ALL SELECT 4,'dd,ccc,c',30
    UNION ALL SELECT 5,'ddaa,ccc',40
    UNION ALL SELECT 6,'eee,ee,c',50
    GO--1. 记录数统计示例
    --分拆处理需要的辅助表(由于是直接处理,所以根据col1列中最大的数据长度来创建)
    DECLARE @len int
    SELECT TOP 1 @len=LEN(col)+1 FROM tb ORDER BY LEN(col) DESC
    IF ISNULL(@len,1)=1 RETURN
    SET ROWCOUNT @len
    SELECT ID=IDENTITY(int,1,1) INTO # FROM syscolumns a,syscolumns b
    ALTER TABLE # ADD PRIMARY KEY(ID)
    SET ROWCOUNT 0--统计处理
    SELECT data=SUBSTRING(a.col,b.ID,CHARINDEX(',',a.col+',',b.ID)-b.ID),
    [COUNT]=COUNT(DISTINCT a.ID),
    Numbers=COUNT(*)
    FROM tb a,# b
    WHERE b.ID<=LEN(a.col)
    AND SUBSTRING(','+a.col,b.ID,1)=','
    GROUP BY SUBSTRING(a.col,b.ID,CHARINDEX(',',a.col+',',b.ID)-b.ID)
    DROP TABLE #
    GO
    /*================================================================*/
    --2. 分拆求和统计示例
    --分拆处理需要的辅助表(由于是直接处理,所以根据col1列中最大的数据长度来创建)
    DECLARE @len int
    SELECT TOP 1 @len=LEN(col)+1 FROM tb ORDER BY LEN(col) DESC
    IF ISNULL(@len,1)=1 RETURN
    SET ROWCOUNT @len
    SELECT ID=IDENTITY(int,1,1) INTO # FROM syscolumns a,syscolumns b
    ALTER TABLE # ADD PRIMARY KEY(ID)
    SET ROWCOUNT 0--统计处理
    SELECT data,SUM_num=SUM(num)
    FROM(
    SELECT DISTINCT
    data=SUBSTRING(a.col,b.ID,CHARINDEX(',',a.col+',',b.ID)-b.ID),
    a.num,a.ID
    FROM tb a,# b
    WHERE b.ID<=LEN(a.col)
    AND SUBSTRING(','+a.col,b.ID,1)=','
    )a GROUP BY data
    DROP TABLE #
    GO
    /*================================================================*/
    --3. 分拆求平均统计示例
    --分拆处理需要的辅助表(由于是直接处理,所以根据col1列中最大的数据长度来创建)
    DECLARE @len int
    SELECT TOP 1 @len=LEN(col)+1 FROM tb ORDER BY LEN(col) DESC
    IF ISNULL(@len,1)=1 RETURN
    SET ROWCOUNT @len
    SELECT ID=IDENTITY(int,1,1) INTO # FROM syscolumns a,syscolumns b
    ALTER TABLE # ADD PRIMARY KEY(ID)
    SET ROWCOUNT 0--统计处理
    SELECT data,
    AVG_num=CAST(AVG(CASE 
    WHEN gid=1 THEN num-CAST(num as float)/(cnt+1)*cnt
    ELSE CAST(num as float)/(cnt+1) END) as decimal(10,2))
    FROM(
    SELECT a.num,gid=b.ID,
    data=SUBSTRING(a.col,b.ID,CHARINDEX(',',a.col+',',b.ID)-b.ID),
    cnt=LEN(a.col)-LEN(REPLACE(a.col,',',''))
    FROM tb a,# b
    WHERE b.ID<=LEN(a.col)
    AND SUBSTRING(','+a.col,b.ID,1)=','
    )a GROUP BY data
    DROP TABLE #
    GO
      

  4.   

    liangCK辛苦了!
    可是我看不懂什么意思。
    其实我是想,有没有类似高级语言里的SPLIT函数。
    在网上找了一下,好像都只能传常量进去,不能传字段名
      

  5.   

    create  function F_split(
                    @s varchar(8000),          --包含多个数据项的字符串
                    @pos int,                 --要获取的数据项的位置
                    @split varchar(10)        --数据分隔符
    )RETURNS varchar(100)
    AS
    BEGIN
        IF @s IS NULL RETURN(NULL)
        DECLARE @splitlen int                --分隔符长度
        SELECT @splitlen=LEN(@split+'a')-2
        WHILE @pos>1 AND charindex(@split,@s+@split)>0
            SELECT @pos=@pos-1,
                @s=stuff(@s,1,charindex(@split,@s+@split)+@splitlen,'')
        RETURN(nullif(left(@s,charindex(@split,@s+@split)-1),''))
    END
    GO---select a,dbo.f_split(a)
    from ta