Linq-Entities:获取不包括重叠数据范围的数据,选择最大的周期

发布于 2024-11-01 17:25:43 字数 865 浏览 0 评论 0原文

我有 2 个表:进口表和期间表。

Imports 具有以下结构:

AdminID, PeriodID, Some more fields
1,       1
1,       2
1,       6
1,       50

周期表具有以下结构:

PeriodID, PeriodType, StartDate,   EndDate,    Description
1,        1,          2007-01-01,  2007-12-31, Year 2007
2,        2,          2007-01-01,  2007-03-31, Quarter 1 2007
3,        2,          2007-04-01,  2007-06-30, Quarter 2 2007
4,        2,          2007-07-01,  2007-09-30, Quarter 3 2007
5,        2,          2007-10-01,  2007-12-31, Quarter 4 2007
6,        3,          2007-01-01,  2007-01-31, January 2007
.
.
.
50,       2,          2011-01-01,  2011-03-31, Quarter 1 2011

现在,我需要构建一个 linq 查询来根据 Imports 表中的数据仅获取最大的周期(忽略较小的重叠周期)!

当我查询 AdminID = 1 时,我应该只得到 periodID = 1 & 50,忽略/排除PeriodIDs 2 & 6,因为它们在 1 和 50 中重叠,因为还没有重叠数据!

I have 2 tables, Imports and Periods.

Imports has the following structure:

AdminID, PeriodID, Some more fields
1,       1
1,       2
1,       6
1,       50

Periods table has the following structure:

PeriodID, PeriodType, StartDate,   EndDate,    Description
1,        1,          2007-01-01,  2007-12-31, Year 2007
2,        2,          2007-01-01,  2007-03-31, Quarter 1 2007
3,        2,          2007-04-01,  2007-06-30, Quarter 2 2007
4,        2,          2007-07-01,  2007-09-30, Quarter 3 2007
5,        2,          2007-10-01,  2007-12-31, Quarter 4 2007
6,        3,          2007-01-01,  2007-01-31, January 2007
.
.
.
50,       2,          2011-01-01,  2011-03-31, Quarter 1 2011

Now, I need to build a linq query to fetch only the largest period(ignoring the smaller overlapping periods) based on the data in Imports table!

When I query for AdminID = 1, I should only get PeriodID = 1 & 50, ignoring/excluding the PeriodIDs 2 & 6 as they overlap in 1 and 50 as there is no overlapping data yet!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

孤独陪着我 2024-11-08 17:25:43

您可以通过正确比较两个表中的 periodID 来最大程度地帮助选择最大期间并检索值。

You, can the max help for picking the largest period and while retrieving the values by comparing the PeriodIDs in both tables right.

浪荡不羁 2024-11-08 17:25:43

我不确定是否有一种方便的方法在数据库中执行此操作,但是当您在本地提取数据时,如果合适的话,您可以执行内存中 LINQ 查询。您需要按照三个步骤执行此操作。

第 1 步:定义一个 Range 类,允许您对周期进行比较(见下文)。

第 2 步:从数据库中提取句点:

var ranges = (
    from period in context.Periods
    where period.Imports.Any(i => i.AdminID == adminId)
    select new Range(period.StartDate, period.EndDate.AddDays(1)))
    .ToArray();

注意 .ToArray() 以在本地提取所有内容。

步骤 3:将所有周期聚合/合并到不重叠周期列表中:

var mergedPeriods = (
    from range in ranges
    select ranges.Where(p => p.OverlapsWith(range))
        .Aggregate((r1, r2) => r1.Merge(r2)))
    .Distinct();

为此,您需要一个专门设计的 Range 类型,其中包含 OverlapsWithMergeEquals 方法。它可能看起来像这样:

public class Range : IEquatable<Range>
{
    public Range(DateTime start, DateTime exclusiveEnd)
    {
        if (exclusiveEnd < start)
            throw new ArgumentException();

        this.Start = start; this.End = exclusiveEnd;
    }

    public DateTime Start { get; private set; }
    public DateTime End { get; private set; }
    public TimeSpan Duration { get { return this.End - this.Start; } }

    public Range Merge(Range other)
    {
        if (!this.OverlapsWith(other)) throw new ArgumentException();

        var start = this.Start < other.Start ? this.Start : other.Start;
        var end = this.End > other.End ? this.End : other.End;

        return new Range(start, end);
    }

    public bool Contains(Range other)
    {
        return this.Start <= other.Start && this.End > other.End;
    }

    public bool OverlapsWith(Range other)
    {
        return this.OverlapsOnStartWith(other) ||
            other.OverlapsOnStartWith(this) ||
            this.Contains(other) ||
            other.Contains(this);
    }

    private bool OverlapsOnStartWith(Range other)
    {
        return this.Start >= other.Start && this.Start < other.End;
    }

    public bool Equals(Range other)
    {
        return this.Start == other.Start && this.End == other.End;
    }
}

我希望这会有所帮助。

I'm not sure whether there is a convenient way to do this in the database, but when you pull the data locally, you can do in-memory LINQ queries, if this is appropriate. You need to do this in thee steps.

Step 1: Define a Range class that allows you to do comparisons on periods (see below).

Step 2: Pulling the periods from the database:

var ranges = (
    from period in context.Periods
    where period.Imports.Any(i => i.AdminID == adminId)
    select new Range(period.StartDate, period.EndDate.AddDays(1)))
    .ToArray();

Note the .ToArray() to pull everything locally.

Step 3: Aggregating / merging all the periods into a list of non-overlapping periods:

var mergedPeriods = (
    from range in ranges
    select ranges.Where(p => p.OverlapsWith(range))
        .Aggregate((r1, r2) => r1.Merge(r2)))
    .Distinct();

For this to work you need a specially designed Range type that contains OverlapsWith, Merge and Equals methods. It might look like this:

public class Range : IEquatable<Range>
{
    public Range(DateTime start, DateTime exclusiveEnd)
    {
        if (exclusiveEnd < start)
            throw new ArgumentException();

        this.Start = start; this.End = exclusiveEnd;
    }

    public DateTime Start { get; private set; }
    public DateTime End { get; private set; }
    public TimeSpan Duration { get { return this.End - this.Start; } }

    public Range Merge(Range other)
    {
        if (!this.OverlapsWith(other)) throw new ArgumentException();

        var start = this.Start < other.Start ? this.Start : other.Start;
        var end = this.End > other.End ? this.End : other.End;

        return new Range(start, end);
    }

    public bool Contains(Range other)
    {
        return this.Start <= other.Start && this.End > other.End;
    }

    public bool OverlapsWith(Range other)
    {
        return this.OverlapsOnStartWith(other) ||
            other.OverlapsOnStartWith(this) ||
            this.Contains(other) ||
            other.Contains(this);
    }

    private bool OverlapsOnStartWith(Range other)
    {
        return this.Start >= other.Start && this.Start < other.End;
    }

    public bool Equals(Range other)
    {
        return this.Start == other.Start && this.End == other.End;
    }
}

I hope this helps.

故事灯 2024-11-08 17:25:43

好吧,经过长期的努力,我确实找到了答案!只需对数据库进行一次查询即可!
并且为了每个人的利益发布相同的内容。

var oImportPeriods = 
    from o in Imports
    where o.Administration.AdminID == 143
    orderby o.Period.PeriodID
    select o.Period;

var oIgnorePeriodList = (
    from oPeriod in oImportPeriods
    from oSearchPeriod in oImportPeriods
        .Where(o => o.PeriodID != oPeriod.PeriodID)
    where oPeriod.StartDate >= oSearchPeriod.StartDate
    where oPeriod.EndDate <= oSearchPeriod.EndDate
    select oPeriod.PeriodID)
    .Distinct();

var oDeletablePeriods = oAdministrationPeriods
    .Where(o => !oIgnorePeriodList.Contains(o.PeriodID));   

foreach(var o in oDeletablePeriods)
    Console.WriteLine(o.Name);

Well, after a long struggle, I did find an answer! With a single query to database!
And for everyone's benefit posting the same.

var oImportPeriods = 
    from o in Imports
    where o.Administration.AdminID == 143
    orderby o.Period.PeriodID
    select o.Period;

var oIgnorePeriodList = (
    from oPeriod in oImportPeriods
    from oSearchPeriod in oImportPeriods
        .Where(o => o.PeriodID != oPeriod.PeriodID)
    where oPeriod.StartDate >= oSearchPeriod.StartDate
    where oPeriod.EndDate <= oSearchPeriod.EndDate
    select oPeriod.PeriodID)
    .Distinct();

var oDeletablePeriods = oAdministrationPeriods
    .Where(o => !oIgnorePeriodList.Contains(o.PeriodID));   

foreach(var o in oDeletablePeriods)
    Console.WriteLine(o.Name);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文