Linq查询与笛卡尔(通缉)和最小/最大在where子句

时间:2014-12-09 19:40:28

标签: linq aggregate

我试图创建一个存储过程的Linq实例,其中一部分让我适合。

这是我试图模仿的SQL:

DECLARE @LookBack = 12,
        @FromDate = GETDATE(),
        @BEGINDATE DATETIME,
        @ENDDATE DATETIME

SELECT  @BEGINDATE = new DateTime(fromDate.Year, fromDate.Month, 1).AddMonths(lookBack * -1),
        @ENDDATE = new DateTime(fromDate.Year, fromDate.Month, fromDate.Day)

DECLARE @BASEINFO TABLE( 
    IDBASEINFO INT IDENTITY(1,1) NOT NULL, -- PRIMARY KEY CLUSTERED, 
    IDACCOUNT INT NOT NULL,         
    BEGINDATE SMALLDATETIME NOT NULL, 
    ENDDATE SMALLDATETIME NOT NULL, 
    GLNUMBER VARCHAR(72) NOT NULL, 
    GLDESCRIPTION VARCHAR(24),
    primary key (IDACCOUNT, GLNUMBER, BEGINDATE, ENDDATE)
) 



--CREATE A TABLE OF DATES FOR EACH DATE IN THE PERIOD BEING EXAMINED 
DECLARE @DATES TABLE (THISDATE SMALLDATETIME) 

DECLARE @aDate SMALLDATETIME 
SELECT  @aDate = @BEGINDATE 

WHILE @aDate <= @ENDDATE 
    BEGIN 
        INSERT  @DATES(THISDATE) VALUES(@aDate) 
        SET     @aDate = DATEADD(DAY, 1, @aDate) 
    END 

--CREATE A TABLE THAT HAS EACH IDACCOUNT AND A CORRESPONDING ROW FOR EACH VALUE IN @DATES 
--WHERE THERE IS NO DATA IN @BASEINFO TO COVER "THISDATE"
DECLARE @GLDATES TABLE ( 
    IDACCOUNT INT, 
    THISDATE SMALLDATETIME, 
    GLNUMBER VARCHAR(72), 
    GLDESCRIPTION VARCHAR(24) 
) 

INSERT INTO @GLDATES 
SELECT  DISTINCT B.IDACCOUNT, 
        D.THISDATE, 
        B.GLNUMBER, 
        B.GLDESCRIPTION 
FROM    @BASEINFO B, 
        @DATES D 
WHERE   D.THISDATE >= 
        ( 
            SELECT  MIN(BEGINDATE) 
            FROM    @BASEINFO 
            WHERE   IDACCOUNT = B.IDACCOUNT 
                    AND GLNUMBER = B.GLNUMBER 
        ) 
        AND D.THISDATE <= 
        ( 
            SELECT  MAX(ENDDATE) 
            FROM    @BASEINFO 
            WHERE   IDACCOUNT = B.IDACCOUNT 
                    AND GLNUMBER = B.GLNUMBER 
        ) 
        AND NOT EXISTS 
        ( 
            SELECT  *   
            FROM    @BASEINFO BSI 
            WHERE   BSI.IDSACCOUNT = B.IDACCOUNT 
                    AND BSI.GLNUMBER = B.GLNUMBER 
                    AND D.THISDATE BETWEEN BSI.BEGINDATE AND BSI.ENDDATE 
        )

这里发生了什么?目标是在整个期间内找到日期/ IDAccount / GL中@BaseInfo中没有任何数据的日期。

创建一个表变量来保存BaseInfo,这最终是我们感兴趣的数据。另一个表变量填充了一段日期,通常是一年,该日期中每天的一个日期。 创建另一个表中两者的笛卡儿,所以我们在@Dates中有一个条目,在@BaseInfo中有一个行。 模仿WHERE子句是我的回避,我可以创建一个代表笛卡儿的对象,但是我正在伤害的最小/最大/存在因素。

到目前为止我的代码:

List<GLDate> glDates =
        (
            from bai in baseAccountInformation
            from d in dateList
            select new GLDate
                   {
                       IDAccount = bai.IDAccount, 
                       ThisDate = d, 
                       GLNumber = bai.GLNumber, 
                       GLDescription = bai.GLDescription
                   }

        ).ToList();

public class GLDate
{
    public int IDAccount { get; set; }
    public DateTime ThisDate { get; set; }
    public string GLNumber { get; set; }
    public string GLDescription { get; set; }
}

处理两个对象之间的最小值/最大值的交叉让我感到困惑,如果进程必须为每一行获得最小值/最大值并创建它自己的对象以进行比较,效率如何那会吗?我已经阅读了关于分组的所有内容并选择了很多内容并且不确定如何继续。

谢谢!

1 个答案:

答案 0 :(得分:0)

我认为最简单的方法是从SQL语句中拆分内部查询 您可以通过执行以下操作来首先检索最小/最大/存在值:

var maxEndDate = baseAccountInformation.Max(x => x.EndDate);
var minBeginDate = baseAccountInformation.Min(x => x.BeginDate);
var filter = baseAccountInformation.Where(...);

然后,您可以在简单的where语句中在LINQ查询中使用这些值 对于过滤器,您需要执行where !filter.Any(x => x == bai)之类的操作 我希望这很清楚。