t-sql选择查询

时间:2010-06-18 20:47:56

标签: sql sql-server tsql sql-server-2008

基于下表

Title Jul-10  Aug-10 Sep-10 Oct-10 Nov-10  Dec-10 Jan-11  Feb-11 Mar-11 Apr-11 May-11 Jun-11
--------------------------------------------------------------------------------------------
A      Null    M1     Null    M2     Null   Null   Null    Null   M3     Null   Null   Null
B      Null    M1     Null    Null   Null   Null   M2      Null   Null   Null   Null   Null
C      Null    Null   Null    Null   Null   M1     Null    Null   Null   Null   Null   Null

如何仅选择特定范围之间的列。

For instance if input variables are:
-------------------------------------
@start = 'Oct-10'
@end = 'Apr-11'

然后输出将是:

Title  Oct-10  Nov-10  Dec-10  Jan-11   Feb-11   Mar-11   Apr-11
-----------------------------------------------------------------
A      M2      Null    Null     Null     Null     M3       Null   
B      Null    Null    Null     M2       Null     Null     Null
C      Null    Null    M1       Null     Null     Null     Null

5 个答案:

答案 0 :(得分:2)

这是应用程序比SQl更有意义的事情。做一个:

 select field1, field2 from your table between date1 and date2. 

然后让应用程序转动数据。通常,应用程序可以比SQL更有效地转动数据。特别是每次运行时列数都不同。

答案 1 :(得分:1)

看起来表是旋转的,我的意思是列应该是行。这种类型的设计非常易读,但不易查询。

看看UNPIVOT运营商。您应该能够使用它来获取包含可以过滤的行的数据集,然后在完成后,如果需要,可以将其重新调整为此格式。

这是一篇文章:http://msdn.microsoft.com/en-us/library/ms177410.aspx

UNPIVOT通过将列旋转到行中来执行几乎PIVOT的反向操作。

答案 2 :(得分:1)

使用名为pivot_query的便捷存储过程,这是一种更简单的方法 (code is hereexamples here)。这样,您可以使用开始日期和结束日期条件来限制要旋转的数据,从而限制在透视后获得的列。

fn_MonthRange() function是递归CTE,它在开始日期和结束日期之间提供一个月份的日期表,然后您将OUTER加入到您的数据中。这将填补任何失踪的月份。

fn_DateRange()类似,但适用于“每15分钟”,每小时,每3天等任意时间段。)

    create table #testdata
       (
       id          integer,
       Title       varchar(20),
       TheDate     datetime,
       Metadata    varchar(20)
       )
    go


    insert into #testdata values(1,'A','08/01/2010','M1')
    insert into #testdata values(1,'A','10/05/2010','M2')
    insert into #testdata values(1,'A','03/15/2011','M3')
    insert into #testdata values(2,'B','09/20/2010','M1')
    insert into #testdata values(2,'B','01/15/2011','M2')
    insert into #testdata values(3,'C','12/15/2010','M1')
    go

    declare @mySQL       varchar(MAX);
    declare @StartDate   varchar(20);
    declare @EndDate     varchar(20);

    set @StartDate = '08/01/2010';
    set @EndDate   = '03/15/2011';

    set @mySQL = '
    select
       id,
       Title,
       Left(Datename(month, TheDate),3) + ''-'' + right(cast(Year(theDate) as varchar(4)),2) monyr,
       Metadata
    from
   dbo.fn_MonthRange( ''' + @StartDate + ''',''' + @EndDate + ''') dr

   LEFT OUTER JOIN #testdata td
      on (td.TheDate between dr.startdate and dr.enddate )
where
   dr.StartDate between ''' + @StartDate + ''' and ''' + @EndDate + '''';

    exec pivot_query @mySQL, 'Title', 'monyr','max(Metadata)'
    go

    Result:
Title                Aug-10               Dec-10               Feb-11               Jan-11               Mar-11               Nov-10               Oct-10               Sep-10               
-------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- 
A                    M1                   NULL                 NULL                 NULL                 M3                   NULL                 M2                   NULL                 
B                    NULL                 NULL                 NULL                 M2                   NULL                 NULL                 NULL                 M1                   
C                    NULL                 M1                   NULL                 NULL                 NULL                 NULL                 NULL                 NULL                 
None                 NULL                 NULL                 None                 NULL                 NULL                 None                 NULL                 NULL                 

答案 3 :(得分:0)

简短的回答是否定的。我做了一些测试。我将为您提供代码,但由于如何使用unpivot处理NULL,您将失去连续的月份范围。它们可以通过枢轴添加回来,但这需要一个数字表等。对我来说做太多了5:02! =)

WITH datepivot
     AS (SELECT title,
                Convert(DATETIME, Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(datecol, 'Jan', '01-01'), 'Feb', '02-01'), 'Mar', '03-01'), 'Apr', '04-01'), 'May', '05-01'), 'Jun', '06-01'), 'Jul', '07-01'), 'Aug', '08-01'), 'Sep', '09-01'), 'Oct', '10-01'), 'Nov', '11-01'), 'Dec', '12-01')) datecol,
                datecol                                                                                                                                                                                                                                                                                                                                origdatecol,
                Isnull(code, 0)                                                                                                                                                                                                                                                                                                                        code
         FROM   (SELECT title,
                        [Jul-10],
                        [Aug-10],
                        [Sep-10],
                        [Oct-10],
                        [Nov-10],
                        [Dec-10],
                        [Jan-11],
                        [Feb-11],
                        [Mar-11],
                        [Apr-11],
                        [May-11],
                        [Jun-11]
                 FROM   test) test UNPIVOT (code FOR datecol IN ([Jul-10], [Aug-10], [Sep-10], [Oct-10], [Nov-10], [Dec-10], [Jan-11], [Feb-11], [Mar-11], [Apr-11], [May-11], [Jun-11]))AS dateunpivot)
--SELECT * from datepivot   --uncomment to view unpivoted data
SELECT *
FROM   (SELECT title,
               code,
               origdatecol
        FROM   datepivot
        WHERE  datecol BETWEEN '10-01-2010' AND '04-01-2011') a PIVOT (Max(code) FOR origdatecol IN ([Jul-10], [Aug-10], [Sep-10], [Oct-10], [Nov-10], [Dec-10], [Jan-11], [Feb-11], [Mar-11], [Apr-11], [May-11], [Jun-11])) b 

答案 4 :(得分:0)

您可以生成必要的SQL select语句,然后使用sp_executesql运行查询。

以下是如何生成月份列名称的示例:

DECLARE  @nextMonth TABLE(
    currentMonth CHAR(3),
    nextMonth CHAR(3)
);

INSERT INTO @nextMonth(currentMonth, nextMonth)
SELECT 'Jan', 'Feb' UNION ALL
SELECT 'Feb', 'Mar' UNION ALL
SELECT 'Mar', 'Apr' UNION ALL
SELECT 'Apr', 'May' UNION ALL
SELECT 'May', 'Jun' UNION ALL
SELECT 'Jun', 'Jul' UNION ALL
SELECT 'Jul', 'Aug' UNION ALL
SELECT 'Aug', 'Sep' UNION ALL
SELECT 'Sep', 'Oct' UNION ALL
SELECT 'Oct', 'Nov' UNION ALL
SELECT 'Nov', 'Dec' UNION ALL
SELECT 'Dec', 'Jan'

DECLARE @start char(6), @end char(6), @current char(6), @columnNames varchar(1000)
SELECT @start = 'Oct-10', @end = 'Apr-11'

SET @current = @start;
WHILE (@current <> @end)
BEGIN
    IF (@columnNames IS NULL)
        SET @columnNames = @current;
    ELSE
        SET @columnNames = @columnNames + ', ' + @current;

    SELECT @current = nextMonth + '-' + LTRIM(STR(case LEFT(@current, 3) WHEN 'Dec' THEN 1+RIGHT(@current, 2) ELSE RIGHT(@current, 2) END))
    FROM @nextMonth
    WHERE currentMonth = left(@current, 3)
END

SELECT @columnNames

这给了我:

Oct-10, Nov-10, Dec-10, Jan-11, Feb-11, Mar-11

可以更明确地增加年份。我利用了自动铸造。

我只能访问SQL Server 2005,所以在2008年可能有更好的方法。

相关问题