若现在有1000张表左右,表结构都是一样的 2列,第一列ID,第二列Con,
表名的增长规则是 [2012-01-01]\[2012-01-02]\[2012-01-03],
以日期为表名的,记录公司每天所有人聊天软件聊天记录,
现在我想查 4月份整月
ID为138的人都所有聊天记录该怎么查呢?
不会要union all 30张表吧?
请大家帮帮忙

解决方案 »

  1.   

    如果不用union all,那就自己拼接SQL语句,动态执行.
      

  2.   

    提种方法你可以参考下,你可以生成一个作业,每天执行一次,这个作业的作用是生成一张视图,视图是UNION所有表内容并附加日期列信息。你的表应该也是每天执行一次的作业,所以在作业里添加生成视图的语句就可以了这样每天作业更新视图内容,而你想查询某一时间段的信息只需要直接从生成的视图里面查询就可以了,不用每次都UNION所有表或者拼接SQL语句了。
    举个例子:CREATE TABLE [2012-03-14]
    (
    ID INT NOT NULL,
    Con VARCHAR(100) NOT NULL
    )INSERT INTO [2012-03-14]
    SELECT 1,'aa' UNION
    SELECT 2,'bb' UNION 
    SELECT 3,'cc' UNION
    SELECT 138,'dd'
    CREATE TABLE [2012-03-15]
    (
    ID INT NOT NULL,
    Con VARCHAR(100) NOT NULL
    )INSERT INTO [2012-03-15]
    SELECT 1,'aa' UNION
    SELECT 2,'bb' UNION 
    SELECT 3,'cc' UNION
    SELECT 138,'dd'
    DECLARE @Table TABLE(Id INT IDENTITY(1,1),TableName VARCHAR(100))
    DECLARE @Total INT
    DECLARE @Line INT
    DECLARE @Sql VARCHAR(8000)
    DECLARE @TableName VARCHAR(100)SET @Line = 1
    INSERT INTO @Table
    SELECT name FROM SYSOBJECTS WHERE name LIKE '20%'SELECT @Total = MAX(Id)
    FROM @TableIF EXISTS (SELECT 1 FROM SYSOBJECTS WHERE name = 'UV_ShowAllTable')
    BEGIN
    DROP VIEW UV_ShowAllTable
    ENDSET @Sql = 'CREATE VIEW UV_ShowAllTable 
    AS 'WHILE @Line <= @Total
    BEGIN SELECT @TableName = TableName FROM @Table WHERE Id = @Line

    SET @Sql = @Sql + '
    SELECT Id,Con,' + '''' + @TableName + '''' + ' AS Date FROM ' + '[' + @TableName + ']'

    IF @Line <> @Total
    BEGIN
    SET @Sql = @Sql + ' UNION '
    END

    SET @Line = @Line + 1

    ENDEXEC (@Sql)SELECT * FROM UV_ShowAllTable
    WHERE ID = 138 AND Date BETWEEN '2012-03-01' AND '2012-03-31'结果
    Id      Con     Date
    138 dd 2012-03-14
    138 dd 2012-03-15
      

  3.   

    谢谢你~这样可以不过有一点
    我DECLARE @Sql VARCHAR(8000) 已经改成MAX了可是SQL还是拼接不下。。肿么办呀
      

  4.   

    /*--化解字符串不能超过8000的方法一
    经常有人提到,用动态生成SQL语句的方法处理数据时,处理语句超长,无法处理的问题
    下面就讨论这个问题:
    --邹建 2003.9(引用请保留此信息)--*/
    /*-- 测试环境
    --以系统表 syscolumns 为测试数据,要求按xtype为列字段,name为行字段,统计colid的和
    --要求结果
    xtype    filedname_1    fieldname_2    .....    fieldname_n
    -------- -------------- -------------- -------- --------------
    34       0              0              .....    1
    --*//*--常规处理方法(不加行数限制会因生成的字符串益出而出错)
    set rowcount 10    --因为syscolumns的记录较,会导致生成的字符串溢出,所以限制一下行数declare @s nvarchar(4000)
    set @s=''
    select @s=@s+N','+quotename([name])
        +N'=sum(case name when '+quotename([name],'''')
        +N' then [colid] else 0 end)'
    from(select distinct [name] from [syscolumns]) aset rowcount 0    --取消限制
    exec(N'select [xtype]'+@s+N' from [syscolumns] group by [xtype]')/*--问题
    不加行数限制时,会因生成的字符串益出而出错
    --*/
    --*//*--方法1. 多个变量处理--根据查询结果定义变量(实际处理中,应该是估计需要多少个变量,定义足够多的变量个数,多定义变量并不影响处理,下面就多定义了一个)
    --生成数据处理临时表
    SELECT id=IDENTITY(int,0,1),
        g=0,
        a=CAST(N','+QUOTENAME([name])
            +N'=SUM(CASE [name] WHEN N'+QUOTENAME(name,N'''')
            +N' THEN [colid] ELSE 0 END)'
            as nvarchar(4000))
    INTO # FROM syscolumns
    WHERE name>N''
    GROUP BY name--分组临时表
    UPDATE a SET G=id/i
    FROM # a,(SELECT i=3800/MAX(LEN(a)) FROM #)b
    SELECT MAX(g)+1 as N'需要的变量个数' FROM #DECLARE @0 nvarchar(4000),@1 nvarchar(4000),@2 nvarchar(4000),@3 nvarchar(4000),@4 nvarchar(4000)
    SELECT @0=N'',@1=N'',@2=N'',@3=N'',@4=N''
    SELECT 
        @0=CASE g WHEN 0 THEN @0+a ELSE @0 END,
        @1=CASE g WHEN 1 THEN @1+a ELSE @1 END,
        @2=CASE g WHEN 2 THEN @2+a ELSE @2 END,
        @3=CASE g WHEN 3 THEN @3+a ELSE @3 END,
        @4=CASE g WHEN 4 THEN @4+a ELSE @4 END
    FROM #
    EXEC(N'SELECT xtype'+@0+@1+@2+@3+@4+N' FROM syscolumns GROUP BY xtype')
    DROP TABLE #/*--方法说明优点:比较灵活,数据量大时只需要增加变量就行了.不用改动其他部分
    缺点:要自行估计处理的数据,估计不足就会出错
    --*/
    --*//*--方法2. bcp+isql--因为要用到bcp+isql,所以需要这些信息
    declare @servername sysname,@username sysname,@pwd sysname
    select @servername=@@servername  --服务器名
        ,@username=N''           --用户名
        ,@pwd=N''                --密码declare @tbname sysname,@s nvarchar(4000)--创建数据处理临时表
    set @tbname=quotename(N'##temp_'+cast(newid() as varchar(36)))
    set @s=N'create table '+@tbname+'(a nvarchar(4000))
    insert into '+@tbname+N'
    select N''create view '
        +stuff(@tbname,2,2,N'')
        +N' as 
    select [xtype]''
    union all
    select N'',''+quotename([name])+''=sum(case [name] when N''
        +quotename([name],'''''''')
        +'' then [colid] else 0 end)''
        from(select distinct [name] from [syscolumns] where name<>N''xtype'')a
    union all
    select N''from [syscolumns] group by [xtype]'''
    exec(@s)--生成创建视图的文件,注意使用了文件:c:\temp.txt
    set @s=N'bcp "'+@tbname+N'" out "c:\'+@tbname+N'" /S"'
        +@servername+N'" /U"'+@username+N'" /P"'+@pwd+N'" /w'
    exec master..xp_cmdshell @s,no_output--调用isql生成数据处理视图
    set @s=N'osql /S"'+@servername
        +case 
            when @username=N'' then N'" /E' 
            else N'" /U"'+@username+N'" /P"'+@pwd+N'"'
        end
        +N' /d"'+db_name()+N'" /i"c:\'+@tbname+'"'
    exec master..xp_cmdshell @s,no_output--删除临时文件
    set @s=N'del "c:\'+@tbname+'"'
    exec master..xp_cmdshell @s,no_output--调用视图,显示处理结果
    set @s=N'drop table '+@tbname+N'
    select * from '+stuff(@tbname,2,2,N'')+N'
    drop view '+stuff(@tbname,2,2,N'')
    exec(@s)/*--方法总结    优点:程序自动处理,不存在判断错误的问题
        缺点:复杂,经过的步骤多,容易出错,而且需要一定的操作员权限
    --*/
    --*/--/*-- 方法3. 多个变量处理,综合了方法1,2的优点,解决了方法1中需要人为判断,增加变量的问题,排除了方法2,需要权限和过程复杂的问题
    DECLARE @sqlhead nvarchar(4000),@sqlend nvarchar(4000)
        ,@sql1 nvarchar(4000),@sql2 nvarchar(4000),@sql3 nvarchar(4000),@sql4 nvarchar(4000)
        ,@i int,@ic nvarchar(10)--生成数据处理临时表
    SELECT id=IDENTITY(int,0,1),
        g=0,
        a=CAST(N','
            +QUOTENAME([name])
            +N'=SUM(CASE [name] WHEN N'
            +QUOTENAME(name,N'''')
            +N' THEN [colid] ELSE 0 END)'
            as nvarchar(4000))
    INTO # FROM(
        SELECT DISTINCT name FROM [syscolumns] WHERE name>N'')a--分组临时表
    UPDATE a SET @i=id/i,g=@i
    FROM # a,(SELECT i=3800/MAX(LEN(a)) FROM #)b
    SET @ic=@i--生成数据处理语句
    SELECT 
        @sqlhead=N''''
            +REPLACE(N'SELECT [xtype]',N'''',N'''''')
            +'''',
        @sqlend=N''''
            +REPLACE(N' FROM [syscolumns] GROUP BY [xtype]',N'''',N'''''')
            +N'''',
        @sql1=N'',@sql2=N'',@sql3=N'',@sql4=N''
    WHILE @ic>=0
        SELECT 
            @sql1=N',@'+@ic+N' nvarchar(4000)'+@sql1,
            @sql2=N',@'+@ic+N'=N'''''+@sql2,
            @sql3=N',@'+@ic
                +N'=CASE g WHEN '+@ic
                +N' THEN @'+@ic+N'+a ELSE @'+@ic
                +N' END'+@sql3,
            @sql4=N'+@'+@ic+@sql4,
            @ic=@ic-1
    SELECT 
        @sql1=STUFF(@sql1,1,1,N''),
        @sql2=STUFF(@sql2,1,1,N''),
        @sql3=STUFF(@sql3,1,1,N''),
        @sql4=STUFF(@sql4,1,1,N'')--执行
    EXEC(N'DECLARE '+@sql1+N'
    SELECT '+@sql2+N'
    SELECT '+@sql3+N' FROM #
    EXEC(N'+@sqlhead+N'+'+@sql4+N'+N'+@sqlend+N')')
    --删除临时表
    DROP TABLE #/*--方法总结
        
        总结了前两种方法的优点,自动判断需要处理的变量数
    --*/
    --*/
      

  5.   

    --化解字符串不能超过8000的方法二--常有人提到,用动态生成SQL语句的方法处理数据时,处理语句超长,无法处理的问题  
    --下面就讨论这个问题:  --创建测试数据
    if exists (select * from dbo.sysobjects where id = object_id(N '[tb] ') and OBJECTPROPERTY(id, N 'IsUserTable ') = 1)  
    drop table [tb]  
    GO  create table tb(单位名称 varchar(10),日期 datetime,销售额 int)  
    insert into tb  
    select 'A单位 ', '2001-01-01 ',100  
    union all select 'B单位 ', '2001-01-02 ',101  
    union all select 'C单位 ', '2001-01-03 ',102  
    union all select 'D单位 ', '2001-01-04 ',103  
    union all select 'E单位 ', '2001-01-05 ',104  
    union all select 'F单位 ', '2001-01-06 ',105  
    union all select 'G单位 ', '2001-01-07 ',106  
    union all select 'H单位 ', '2001-01-08 ',107  
    union all select 'I单位 ', '2001-01-09 ',108  
    union all select 'J单位 ', '2001-01-11 ',109  /*要求结果  
    日期       A单位 B单位 C单位 D单位 E单位 F单位 G单位 H单位 I单位 J单位    
    ---------- ----- ----- ----- ----- ----- ----- ----- ----- ----- ------
    2001-01-01 100   0     0     0     0     0     0     0     0     0  
    2001-01-02 0     101   0     0     0     0     0     0     0     0  
    2001-01-03 0     0     102   0     0     0     0     0     0     0  
    2001-01-04 0     0     0     103   0     0     0     0     0     0  
    2001-01-05 0     0     0     0     104   0     0     0     0     0  
    2001-01-06 0     0     0     0     0     105   0     0     0     0  
    2001-01-07 0     0     0     0     0     0     106   0     0     0  
    2001-01-08 0     0     0     0     0     0     0     107   0     0  
    2001-01-09 0     0     0     0     0     0     0     0     108   0  
    2001-01-11 0     0     0     0     0     0     0     0     0     109  
    */  --常规处理方法
    declare @sql varchar(8000)  
    set @sql= 'select 日期=convert(varchar(10),日期,120) '  
    select @sql=@sql+ ',[ '+单位名称  
    + ']=sum(case 单位名称 when ' ' '+单位名称+ ' ' ' then 销售额 else 0 end) '  
    from(select distinct 单位名称 from tb) a  
    exec(@sql+ ' from tb group by convert(varchar(10),日期,120) ')  --问题: 如果单位很多,这时,@SQL的值就会被截断,从而出错.
    --下面给出三种解决办法:  
    --方法1. 多个变量处理  
    --定义变量,估计需要多少个变量才能保存完所有数据  
    declare @sql0 varchar(8000),@sql1 varchar(8000)  
    --,...@sqln varchar(8000)  --生成数据处理临时表  
    select id=identity(int,0,1),groupid=0  
    ,值= ',[ '+单位名称 + ']=sum(case 单位名称 when ' ' '  
    +单位名称+ ' ' ' then 销售额 else 0 end) '  
    into #temp from(select distinct 单位名称 from tb) a  --分组临时表,判断慨最多多少个单位可以组合成一个不超过8000的字符串,这里取假设为5个  
    update #temp set groupid=id/5   --5为每组的单位个数  --生成SQL语句处理字符串  
    --初始化  
    select @sql0= ' '  
    ,@sql1= ' '  
    -- ...  
    -- ,@sqln  --得到处理字符串  
    select @sql0=@sql0+值 from #temp where groupid=0   --第一个变量  
    select @sql1=@sql1+值 from #temp where groupid=1   --第二个变量  
    --select @sqln=@sqln+值 from #temp where groupid=n   --第n个变量  --查询  
    exec( 'select 日期=convert(varchar(10),日期,120) '  
    +@sql0+@sql1  
    -- ...+@sqln  
    + ' from tb group by convert(varchar(10),日期,120)  
    ')  --删除临时表  
    drop table #temp  /*  
    优点:比较灵活,数据量大时只需要增加变量就行了.不用改动其他部分  
    缺点:要自行估计处理的数据,估计不足就会出错  
    */  --方法2. bcp+isql  
    --因为要用到bcp+isql,所以需要这些信息  
    declare @servername varchar(250),@username varchar(250),@pwd varchar(250)  
    select @servername= 'zj '   --服务器名  
    ,@username= ' '   --用户名  
    ,@pwd= ' '     --密码  declare @tbname varchar(50),@sql varchar(8000)  --创建数据处理临时表  
    set @tbname= '[##temp_ '+convert(varchar(40),newid())+ '] '  
    set @sql= 'create table '+@tbname+ '(值 varchar(8000))  
    insert into '+@tbname+ ' values( ' 'create view '  
    +stuff(@tbname,2,2, ' ')+ ' as  
    select 日期=convert(varchar(10),日期,120) ' ') '  
    exec(@sql)  set @sql= 'insert into '+@tbname+ '  
    select ' ',[ ' '+单位名称+ ' ']=sum(case 单位名称 when ' ' ' ' ' '  
    +单位名称+ ' ' ' ' ' ' then 销售额 else 0 end) ' '  
    from(select distinct 单位名称 from tb) a '  
    exec(@sql)  set @sql= 'insert into '+@tbname+ '  
    values( ' 'from tb group by convert(varchar(10),日期,120) ' ') '  
    exec(@sql)  --生成创建视图的文件,注意使用了文件:c:\temp.txt  
    set @sql= 'bcp ' '+@tbname+ '' out 'c:\temp.txt' /S' '  
    +@servername+ '' /U' '+@username+ '' /P' '+@pwd+ '' /c '  
    exec master..xp_cmdshell @sql  --删除临时表  
    set @sql= 'drop table '+@tbname  
    exec(@sql)  --调用isql生成数据处理视图  
    set @tbname=stuff(@tbname,2,2, ' ')  
    set @sql= 'isql /S' '+@servername  
    +case @username when ' ' then '' /E ' else '' /U' '+@username+ '' /P' '+@pwd+ '' ' end  
    + ' /d' '+db_name()+ '' /i'c:\temp.txt' '  exec master..xp_cmdshell @sql  --调用视图,显示处理结果  
    set @sql= 'select * from '+@tbname+ '  
    drop view '+@tbname  
    exec(@sql)  /*  
    优点:程序自动处理,不存在判断错误的问题  
    缺点:复杂,经过的步骤多,容易出错,而且需要一定的操作员权限  
    */  --方法3. 多个变量处理,综合了方法1及方法2的优点, 解决了方法1中需要人为判断的问题,自动根据要处理的数据量进行变量定义,同时又避免了方法2的繁琐  declare @sqlhead varchar(8000),@sqlend varchar(8000)  
    ,@sql1 varchar(8000),@sql2 varchar(8000),@sql3 varchar(8000),@sql4 varchar(8000)  
    ,@i int,@ic varchar(20)  --生成数据处理临时表  
    select id=identity(int,0,1),gid=0  
    ,a= ',[ '+单位名称 + ']=sum(case 单位名称 when ' ' '  
    +单位名称+ ' ' ' then 销售额 else 0 end) '  
    into # from(select distinct 单位名称 from tb) a  --判断需要多少个变量来处理  
    select @i=max(len(a)) from #  
    print @i  
    set @i=7800/@i  --分组临时表  
    update # set gid=id/@i  
    select @i=max(gid) from #  --生成数据处理语句  
    select @sqlhead= ' ' 'select 日期=convert(varchar(10),日期,120) ' ' '  
    ,@sqlend= ' ' ' from tb group by convert(varchar(10),日期,120) ' ' '  
    ,@sql1= ' ',@sql2= 'select ',@sql3= ' ',@sql4= ' '  while @i > =0  
    select @ic=cast(@i as varchar),@i=@i-1  
      ,@sql1= '@ '+@ic+ ' varchar(8000), '+@sql1  
      ,@sql2=@sql2+ '@ '+@ic+ '= ' ' ' ', '  
      ,@sql3= 'select @ '+@ic+ '=@ '+@ic+ '+a from # where gid= '+@ic  
      +char(13)+@sql3  
      ,@sql4=@sql4+ ',@ '+@ic  select @sql1= 'declare '+left(@sql1,len(@sql1)-1)+char(13)  
    ,@sql2=left(@sql2,len(@sql2)-1)+char(13)  
    ,@sql3=left(@sql3,len(@sql3)-1)  
    ,@sql4=substring(@sql4,2,8000)  --执行  
    exec( @sql1+@sql2+@sql3+ '  
    exec( '+@sqlhead+ '+ '+@sql4+ '+ '+@sqlend+ ') '  
    )  --删除临时表  
    drop table #  --方法3中,关键要做修改的是下面两句,其他基本上不用做改变:  
    --生成数据处理临时表,修改a=后面的内容为相应的处理语句  
    select id=identity(int,0,1),gid=0  
    ,a= ',[ '+code+ ']=sum(case b.c_code when ' ' '  
    +code+ ' ' ' then b.value else 0 end) '  
    into # from #Class  --生成数据处理语句,将@sqlhead,@sqlend赋值为相应的处理语句头和尾  
    select @sqlhead= ' ' 'select a.id,a.name,a.code ' ' '  
    ,@sqlend= ' ' ' from #Depart a,#Value b where a.Code=b.d_Code group by a.id,a.code,a.name ' ' '  
    ,@sql1= ' ',@sql2= 'select ',@sql3= ' ',@sql4= ' '