2016-01-28 109 views
4

我有一張記錄表在SQL Server 2008R2中保存守衛巡邏。在子查詢中計數記錄

每當一個任務開始時創建一個新的警報號碼,並且在這個警報號碼內有一個開始時間的巡邏。

每12小時我們可以在至少一次巡邏時進行統一費率。當在相同的警報號下超過12小時的範圍時,必須收取進一步的統一費用。

12小時的計算從第一次巡視的時間開始。

我試着用臨時表,但目前無法解決它。

DECLARE @t1 TABLE (
    AlertNo INT, 
    Starttime SMALLDATETIME, 
    Endtime SMALLDATETIME 
) 

INSERT INTO @t1 (AlertNo, Starttime, Endtime) 

SELECT AlertNo, 
     Starttimepatrol, 
     DATEADD(HOUR, 12, Starttimepatrol) 
FROM tblAllPatrols 
WHERE PatrolNo = 1 

SELECT AlertNo, 
     (
      SELECT COUNT(*) 
      FROM [tblAllPatrols] a 
      INNER JOIN @t1 b ON b.AlertNo = a.AlertNo 
      WHERE a.Starttimepatrol BETWEEN b.Starttime AND b.Endtime 
     ) AS patrols 
FROM [vwAlleDatensaetze] 
GROUP BY AlertNo 

我知道,這不是故事的結束,但我不能即便算上巡邏的數字我不能找到一種方法來解決這個問題。

它應該以某種方式對每個警報號碼的12小時範圍內的巡邏進行「分組」,然後統計在相同警報號下存在多少組。

希望,你們中的某個人可以帶我到我需要的結果。

感謝您的幫助 邁克爾

+0

看看您的需求,似乎要決定巡邏隊是開始新的結算任務還是屬於之前的任務,您需要查看先前的所有巡邏和職責(如果巡邏總是從0開始,這可能是固定的:00/12:00)。因此,我認爲你不應該嘗試在SQL Server中做到這一點,我建議你在一個單獨的應用程序中做這個異步。 –

+0

嗯,我可以用VBA解決它,但是它必須在服務器端完成,它應該創建一個插入另一個表的結果記錄。巡邏隨時開始,警報號碼是客戶的一種訂單,可能會持續幾天甚至更長時間。 – mak

+0

tblAllPatrols有沒有結束時間?如果沒有,那麼你怎麼知道巡邏隊何時結束? – BateTech

回答

0

試試這個,它假定的第一巡邏後的計費週期爲8個小時,從這個時間的倍數:

SQL Fiddle

MS SQL Server 2008中架構設置

查詢1

DECLARE @Patrols TABLE 
(
    AlertNo INT IDENTITY PRIMARY KEY, 
    StartTime DateTime 
) 

INSERT INTO @Patrols (StartTime) 
VALUES ('20160126 09:57'), 
     ('20160126 10:21'), 
     ('20160126 19:54'), 
     ('20160126 23:21'), 
     ('20160127 08:13'), 
     ('20160127 16:43'), 
     ('20160128 07:33') 

;WITH FirstBillingPeriodCTE 
AS 
(
    SELECT MIN(StartTime) as BillingStartTime, 
      DateAdd(HOUR, 12, MIN(StartTime)) As BillingEndTime, 
      1 As BillingPeriod 
    FROM @Patrols 
), 
Numbers 
As 
(
    SELECT num 
    FROM (Values (0),(1), (2), (3), (4), (5), (6), (7), (8), (9)) AS n(Num) 
), 
BillingPeriodsCTE 
AS 
(
    SELECT DATEADD(Hour, 8 * (BillingPeriod + Numbers.Num), BillingStartTime) AS BillingStartTime, 
      DATEADD(Hour, 8 * (BillingPeriod + Numbers.Num), BillingEndTime) AS BillingEndTime, 
      BillingPeriod + Numbers.Num As BillingPeriod 
    FROM FirstBillingPeriodCTE 
    CROSS JOIN Numbers 
) 
SELECT COUNT(DISTINCT BillingPeriod) 
FROM @Patrols P 
INNER JOIN BillingPeriodsCTE B 
    ON P.StartTime >= B.BillingStartTime AND P.StartTime < B.BillingEndTime 

Results

| | 
|---| 
| 4 | 
+0

史蒂夫,我試過你的解決方案,它工作正常。非常感謝! – mak

0

這裏是一個查詢,將給予每個計費週期,最高可達65,535計費時段,精確到秒。

我的解決方案使用計算出的「Tally」表,但從長遠來看,您最好在數據庫中創建自己的物理「Tally」表。有關更多詳細信息,請參見What is the best way to create and populate a numbers table?

您應該可以用您的巡視表替換@tblPatrols

DECLARE @tblPatrols TABLE (alertNo int, startTime datetime); 
DECLARE @hoursPerBillingPeriod int, @toHoursConversion float; 
SET @hoursPerBillingPeriod = 12; 
SET @toHoursConversion = 60 * 60; 

INSERT INTO @tblPatrols (alertNo, startTime) 
VALUES 
    (1, '2016-01-28 05:57') 
, (1, '2016-01-28 07:23') 
, (1, '2016-01-28 08:10') 
, (2, '2016-01-28 09:05') 
, (2, '2016-01-28 12:22') 
, (2, '2016-01-28 16:06') 
, (2, '2016-01-28 23:45') 
, (2, '2016-01-29 00:05') 
, (3, '2016-01-28 12:00') 
, (3, '2016-01-28 16:06') 
, (3, '2016-01-29 00:00') 
, (4, '2016-01-28 12:00') 
, (4, '2016-01-28 16:06') 
, (4, '2016-01-28 23:59:59.997') 
; 

;WITH 
--...................... 
--This section used to simulate a "Tally" table... you would be better off to Create a physical Tally table 
-- see: https://stackoverflow.com/questions/1393951/what-is-the-best-way-to-create-and-populate-a-numbers-table 
    Pass0 as (select 1 as C union all select 1) --2 rows 
, Pass1 as (select 1 as C from Pass0 as A, Pass0 as B) --4 rows 
, Pass2 as (select 1 as C from Pass1 as A, Pass1 as B) --16 rows 
, Pass3 as (select 1 as C from Pass2 as A, Pass2 as B) --256 rows 
, Pass4 as (select 1 as C from Pass3 as A, Pass3 as B)--65536 rows 
, Tally as (select row_number() over(order by C) - 1 as N from Pass4) --65536 rows 
--........................ 
,cteNumBillings as (
    SELECT fp.alertNo 
     , firstPatrolTime = min(fp.startTime) 
     , lastPatrolTime = max(fp.startTime) 
     , hoursBetweenStartMinMax = datediff(second, min(fp.startTime), max(fp.startTime))/@toHoursConversion 
     , numberOfBillingPeriods = floor(((datediff(second, min(fp.startTime), max(fp.startTime))/@toHoursConversion)/@hoursPerBillingPeriod) + 1) 
    FROM @tblPatrols fp 
    GROUP BY fp.alertNo 
) 
SELECT b.alertNo 
    --This is the "x" value of the expression "Billing Period x of y" 
    , BillingPeriodNumber = t.N + 1 
    , BillingPeriodPatrolCount = 
      (select count(*) 
       from @tblPatrols p 
       where p.alertNo = b.alertNo 
       and p.startTime >= dateadd(hour, 12 * t.N, b.firstPatrolTime) 
       and p.startTime < dateadd(hour, 12 * (t.N+1), b.firstPatrolTime) 
      ) 
    , BillingStart = dateadd(hour, 12 * t.N, b.firstPatrolTime) 
    , BillingEnd = dateadd(second, -1, dateadd(hour, 12 * (t.N + 1), b.firstPatrolTime)) 
    --This is the "y" value of the expression "Billing Period x of y" 
    , TotalBillingPeriodCount = b.numberOfBillingPeriods 
FROM cteNumBillings b 
INNER JOIN Tally t ON t.N >= 0 and t.N < b.numberOfBillingPeriods 
ORDER BY 1,2 
; 
+0

非常感謝,我會在假期回來的時候嘗試。 Michael – mak

+0

BateTech,它適合我。非常感謝! – mak

0

我自己找到了一個解決方案,這似乎更容易,我找不到任何使用它的錯誤。 我把第一次巡邏的第一個Startime放在一個變量中。然後我用DATEDIFF爲所有StartTimePatrol的模具差與第一巡邏STARTIME和12小時

set @BillingPeriod=(select (datediff(hour,@StartTime,@StartTimePatrol)/12)+1) 

然後除以它,我把每個記錄的結果在臨時表

insert into @t2 (Alertno, Starttime, Billings) 
values (@Alertno, @StartTimePatrol, @BillingPeriod) 

然後我將altertno和Billings分組並計數它們

select alertno, count(Billings) from (select alertno, Billings from @t2 
group by alertno, Billings) temp group by alertno 

結果對我來說看起來是正確的。

感謝您的回覆。 Michael

+0

這似乎需要很多步驟才能實現,在單個語句中可以實現什麼!看到我的答案 –