2017-11-29 8 views
1

私はSQLでかなり新しくなっています。タイムスタンプが複数の月に重複しているかどうかを判断し、毎月の相対時間を計算する

私はさまざまな活動のdatetimeスタンプを持つデータセットを持っています。

は例えば、私はプロジェクトの寿命の任意の時点で作業が複数ヶ月をまたがるかどうかを判断したい次のフィールド

start_project [datetime] 
finish_project [datetime] 
verify_project [datetime] 

とプロジェクトのリストを持っています。

たとえば、start_projectはJan 1の午前9時に開始し、finish_projectは2月3日の午後12時に、verify_projectは2月12日の午後3時に開始できます。

プロジェクトの月ごとにどれくらいの時間が費やされたかを知りたいので、これらの期間を月ごとにビンすることができます。私は論理をどのように実装するのか分かります。

+1

は、MySQLやSQL Serverのですか?あなたのタグを編集することができますか? – bradbury9

+0

@ bradbury9それはSQLサーバーです。私は反映するために私のタグを編集しました。 – user75514

+0

私が考えている可能性のある唯一のアプローチは、カーソルを使用して各レコードを1つずつ調べ、関連するフィールドが月をオーバーラップしているかどうかを判断することですが、できるだけカーソルを避けようとしています。 – user75514

答えて

0

営業日を含むdimDateテーブルを作成する必要があります。例

Date  isBusinessDay 
1/1/2017 0 
1/2/2017 1 
... 

については

そして、それを照会:

select Month(Date) Month,YEAR(Date) Year, WorkingHours = Count(*)*8 --Assuming 8 bus hours in a day 
from DimDate 
where Date between StartDate and EndDate 
    and isBusinessDay=1 
group by Month(Date),YEAR(Date) 

あなたが適用横断する必要がある、あなたのベースのクエリに追加するには:

select BaseTable.*, a.Month,a.Year, a.WorkingHours 
from BaseTable 
cross apply(
select Month(Date) Month,YEAR(Date) Year, WorkingHours = Count(*)*8 --Assuming 8 bus hours in a day 
    from DimDate 
    where Date between BaseTable.StartDate and BaseTable.EndDate 
     and isBusinessDay=1 
    group by Month(Date),YEAR(Date)) a 
+0

私は24時間の日がほしいと思う。 * 8から* 24に変更するだけです – KeithL

0

番号テーブルでは、これがあります比較的まっすぐ進む...

https://www.mssqltips.com/sqlservertip/4176/the-sql-server-numbers-table-explained--part-1/

次のクエリがうまくいく...
- プロジェクト全体が
にまたがる何ヶ月 - - スパン月
ごとに1つのローを返し - 日付付加し、各プロジェクトは
に始まっ月月には、新たなフィールドとして、新しい行/フィールド上のあなたの心のコンテンツにDATEDIFF()を使用することができます

SELECT 
    yourTable.*, 
    CASE 
     WHEN months_since_start.id = 0 
     THEN yourTable.start_project 
     ELSE DATEADD(month, months_since_start.id, first_month.start) 
    END 
     AS partial_month_start 
FROM 
    yourTable 
CROSS APPLY 
(
    VALUES(DATEADD(month, DATEDIFF(month, 0, yourTable.start_project))) 
) 
    first_month(start) 
INNER JOIN 
    dbo.numbers AS months_since_start 
     ON months_since_start.id >= 0 
     AND months_since_start.id <= DATEDIFF(month, yourTable.start_project, yourTable.verify_project) 

編を開始しました。

0

私はおそらく数字テーブルを使用していたはずですが、これも機能します。

CREATE TABLE #myTable(ProjName VARCHAR(100), start_project DATETIME, finish_project DATETIME, verify_project DATETIME) 

INSERT INTO #myTable SELECT 'proj1', '2017-01-01', '2017-04-15', '2017-04-15' 
INSERT INTO #myTable SELECT 'proj2', '2017-01-02', '2017-01-11', '2017-01-11' 
INSERT INTO #myTable SELECT 'proj3', '2017-06-06', '2017-06-06', '2017-06-06' 
INSERT INTO #myTable SELECT 'proj4', '2017-03-01', '2017-08-15', '2017-08-15' 

;with cte1 AS (
SELECT CASE 
     WHEN CAST(YEAR(t.start_project) AS VARCHAR) + CAST(MONTH(t.start_project) AS VARCHAR) <> CAST(YEAR(t.finish_project) AS VARCHAR) + CAST(MONTH(t.finish_project) AS VARCHAR) 
      THEN (DATEDIFF(DAY, start_project,EOMONTH(start_project, 0)) * 8) + 8 
     WHEN start_project = finish_project 
      THEN 8 
     ELSE (DATEDIFF(DAY, start_project,finish_project) * 8) + 8 
     END AS hours_this_month 
     , DATENAME(MONTH,start_project) AS month_name 
     , 0 AS month_level, start_project, finish_project, ProjName, verify_project 
FROM #myTable t 
UNION ALL 
SELECT CASE 
     WHEN t.finish_project > EOMONTH(DATEADD(MONTH, t.month_level + 1, t.start_project)) 
         AND (CAST(YEAR(t.start_project) AS VARCHAR) + CAST(MONTH(t.start_project) AS VARCHAR) <> CAST(YEAR(t.finish_project) AS VARCHAR) + CAST(MONTH(t.finish_project) AS VARCHAR)) 
      THEN 
      (DATEDIFF(DAY, CAST(CAST(YEAR(DATEADD(MONTH, t.month_level + 1, t.start_project)) AS VARCHAR) + '-' + 
       CAST(MONTH(DATEADD(MONTH, t.month_level + 1, t.start_project)) AS VARCHAR) + '-01' AS DATETIME) 
        , EOMONTH(DATEADD(MONTH, t.month_level + 1, t.start_project))) * 8) + 8 
     ELSE 
      (DATEDIFF(DAY, CAST(CAST(YEAR(DATEADD(MONTH, t.month_level + 1, t.start_project)) AS VARCHAR) + '-' + 
       CAST(MONTH(DATEADD(MONTH, t.month_level + 1, t.start_project)) AS VARCHAR) + '-01' AS DATETIME) 
        , t.finish_project) * 8) + 8 
     END 
     , DATENAME(MONTH,DATEADD(MONTH, t.month_level + 1, t.start_project)) 
     , t.month_level + 1 
     , t.start_project 
     , t.finish_project, t.ProjName, t.verify_project 
FROM cte1 t INNER JOIN 
    #myTable myT ON myT.ProjName = t.ProjName 
WHERE CAST(CAST(YEAR(DATEADD(MONTH, t.month_level + 1, t.start_project)) AS VARCHAR) + '-' + 
     CAST(MONTH(DATEADD(MONTH, t.month_level + 1, t.start_project)) AS VARCHAR) + '-01' AS DATETIME) 
     <= t.finish_project) 
SELECT ProjName 
    , month_name 
    , hours_this_month 
    , start_project 
    , finish_project 
    , verify_project 
    , month_level 
FROM cte1 
ORDER BY ProjName, month_level ASC 

出力...

proj1 January 248 2017-01-01 00:00:00.000 2017-04-15 00:00:00.000 2017-04-15 00:00:00.000 0 
proj1 February 224 2017-01-01 00:00:00.000 2017-04-15 00:00:00.000 2017-04-15 00:00:00.000 1 
proj1 March 248 2017-01-01 00:00:00.000 2017-04-15 00:00:00.000 2017-04-15 00:00:00.000 2 
proj1 April 120 2017-01-01 00:00:00.000 2017-04-15 00:00:00.000 2017-04-15 00:00:00.000 3 
proj2 January 80  2017-01-02 00:00:00.000 2017-01-11 00:00:00.000 2017-01-11 00:00:00.000 0 
proj3 June  8  2017-06-06 00:00:00.000 2017-06-06 00:00:00.000 2017-06-06 00:00:00.000 0 
proj4 March 248 2017-03-01 00:00:00.000 2017-08-15 00:00:00.000 2017-08-15 00:00:00.000 0 
proj4 April 240 2017-03-01 00:00:00.000 2017-08-15 00:00:00.000 2017-08-15 00:00:00.000 1 
proj4 May  248 2017-03-01 00:00:00.000 2017-08-15 00:00:00.000 2017-08-15 00:00:00.000 2 
proj4 June  240 2017-03-01 00:00:00.000 2017-08-15 00:00:00.000 2017-08-15 00:00:00.000 3 
proj4 July  248 2017-03-01 00:00:00.000 2017-08-15 00:00:00.000 2017-08-15 00:00:00.000 4 
proj4 August 120 2017-03-01 00:00:00.000 2017-08-15 00:00:00.000 2017-08-15 00:00:00.000 5 
関連する問題