sql >> データベース >  >> RDS >> Sqlserver

SQL クエリ - 日付範囲に基づいてデータを収集 - 可能な可変数の列

    これは面白かったです。これはあなたが探しているものになると思います。最初のテスト データ:

    CREATE TABLE people (PersonID int, Name varchar(30))
    
    INSERT INTO people (PersonID, Name)
    SELECT 1, 'Kelly'
    UNION ALL SELECT 2, 'Dave'
    UNION ALL SELECT 3, 'Mike'
    
    CREATE TABLE attendances (PersonID int, SignIn datetime, SignOut datetime)
    
    INSERT INTO attendances (PersonID, SignIn, SignOut)
    SELECT 1, '1-Feb-2015 08:00', '1-Feb-2015 09:00'
    UNION ALL SELECT 1, '1-Feb-2015 12:00', '1-Feb-2015 12:30'
    UNION ALL SELECT 2, '2-Feb-2015 08:00', '2-Feb-2015 08:15'
    UNION ALL SELECT 1, '3-Feb-2015 08:00', '3-Feb-2015 09:00'
    UNION ALL SELECT 1, '4-Feb-2015 08:00', '4-Feb-2015 08:30'
    UNION ALL SELECT 2, '4-Feb-2015 08:00', '4-Feb-2015 10:00'
    UNION ALL SELECT 2, '6-Feb-2015 12:00', '6-Feb-2015 15:00'
    UNION ALL SELECT 3, '6-Feb-2015 15:00', '6-Feb-2015 17:00'
    UNION ALL SELECT 3, '8-Feb-2015 10:00', '8-Feb-2015 12:00'
    

    次に、動的クエリ:

    DECLARE @startDate DATETIME='1-Feb-2015'
    DECLARE @endDate DATETIME='9-Feb-2015'
    DECLARE @numberOfDays INT = DATEDIFF(DAY, @startDate, @endDate)
    
    declare @dayColumns TABLE (delta int, colName varchar(12))
    
    -- Produce 1 row for each day in the report. Note that this is limited by the 
    -- number of objects in sysobjects (which is about 2000 so it's a high limit)
    -- Each row contains a delta date offset, @startDate+delta gives each date to report 
    -- which is converted to a valid SQL column name in the format colYYYYMMDD
    INSERT INTO @dayColumns (delta, colName)
    SELECT delta, 'col'+CONVERT(varchar(12),DATEADD(day,delta,@startDate),112) as colName from (
      select (ROW_NUMBER() OVER (ORDER BY sysobjects.id))-1 as delta FROM sysobjects 
    ) daysAhead
    WHERE delta<[email protected]
    
    -- Create a comma seperated list of columns to report
    DECLARE @cols AS NVARCHAR(MAX)= ''
    SELECT @cols=CASE WHEN @cols='' THEN @cols ELSE @cols+',' END + colName FROM @dayColumns ORDER BY delta
    DECLARE @totalHours AS NVARCHAR(MAX)= ''
    SELECT @totalHours=CASE WHEN @totalHours='' THEN '' ELSE @totalHours+' + ' END + 'ISNULL(' + colName +',0)' FROM @dayColumns ORDER BY delta
    
    -- Produce a SQL statement which outputs a variable number of pivoted columns
    DECLARE @query AS NVARCHAR(MAX)
    SELECT @query=
    'declare @days TABLE (reportDay date, colName varchar(12))
    
    INSERT INTO @days (reportDay, colName)
    SELECT DATEADD(day,Delta,'''+CONVERT(varchar(22),@startDate,121)+'''), ''col''+CONVERT(varchar(12),DATEADD(day,delta,'''+CONVERT(varchar(22),@startDate,121)+'''),112) as colName from (
      select (ROW_NUMBER() OVER (ORDER BY sysobjects.id))-1 as Delta FROM sysobjects 
    ) daysAhead
    WHERE Delta<='+CAST(@numberOfDays as varchar(10))+'
    
    SELECT p.Name, pivotedAttendance.*,'[email protected]+' as totalHours FROM (
      SELECT * FROM (
        select p.PersonID, d.colName, CAST(DATEDIFF(MINUTE, a.SignIn, a.SignOut)/60.0 as decimal(5,1)) as hrsAttendance 
        from @days d
        CROSS JOIN people p 
        LEFT OUTER JOIN attendances a ON a.PersonID=p.PersonID AND CAST(a.SignOut as DATE)=d.reportDay
      ) as s
      PIVOT (
        SUM(hrsAttendance) FOR colName in ('[email protected]+')
      ) as pa
    ) as pivotedAttendance
    INNER JOIN people p on p.PersonID=pivotedAttendance.PersonID'
    
    -- Run the query
    EXEC (@query)
    

    これにより、レポート範囲内のすべての日と各人物の行を含む、例と同様の形式でデータが生成されます。上記から、次のことがわかります:

    プレゼンテーションの目的で、列名を表示可能な日付に変換できる必要があります (列名から YYYYMMDD を解析するだけです)。無効な列名が生成されるため、日付を列名として直接使用することはできません。

    SQL Fiddle の例 こちら .



    1. Windows環境でJava用のWebホストを提案する

    2. GROUPBY後の行数を取得します

    3. データベースが更新されたときにプログラムに通知するにはどうすればよいですか?

    4. プリペアドステートメントまたはQueryRunner.update()でテーブルまたは列名のパラメーターを指定することはできますか?