Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Finden Sie die Gesamtminuten, ignorieren Sie die Überlappung (Cursor-basierte Antwort in CTE umwandeln)

Die folgende Abfrage findet die Perioden in den Daten gemäß Ihrer Definition. Es verwendet zuerst korrelierte Unterabfragen, um festzustellen, ob ein Datensatz der Beginn eines Zeitraums ist (d. h. keine Überschneidung mit früheren Zeiträumen). Dann weist es "periodStart" als den jüngsten Start zu, der der Beginn einer sich nicht überschneidenden Periode ist.

Die folgende (ungetestete) Abfrage verfolgt diesen Ansatz:

with TimeWithOverlap as (
     select t.*,
            (case when exists (select * from dbo.Available tbefore where t.availStart > tbefore.availStart and tbefore.availEnd >= t.availStart)
                  then 0
                  else 1
             end) as IsPeriodStart
     from dbo.Available t 
    ),
    TimeWithPeriodStart as (
     select two.*,
            (select MAX(two1.AvailStart) from TimeWithOverlap two1 where IsPeriodStart = 1 and two1.AvailStart <= two.AvailStart
            ) as periodStart
     from TimeWithOverlap two
    )
select periodStart, MAX(AvailEnd) as periodEnd
from TimeWithPeriodStart twps
group by periodStart;

http://sqlfiddle.com/#!6/3483c/20 (Zweite Abfrage)

Wenn zwei Perioden gleichzeitig beginnen, funktioniert es trotzdem, weil die AvailStart-Werte gleich sind. Aufgrund der korrelierten Unterabfragen funktioniert dies möglicherweise selbst bei mittelgroßen Datensätzen nicht sehr gut.

Es gibt andere Methoden, um sich dem zu nähern. Wenn Sie beispielsweise SQL Server 2012 hätten, könnten Sie kumulative Summenfunktionen verwenden, die eine einfachere Methode bieten.