根据标准返回某些记录(2)

时间:2017-03-30 09:45:38

标签: c# sql linq

我之前问了这个问题,但错过了我问题的一个重要部分。

Return certain record based on criteria

获取此结果列表

Client  |   Date     | YESorNO
-------------------------------
A1      | 01/01/2001 | NO
A1      | 01/01/2002 | NO
A1      | 01/01/2003 | YES
A1      | 01/01/2004 | NO
A1      | 01/01/2005 | NO
A1      | 01/01/2006 | NO
A1      | 01/01/2007 | YES
A1      | 01/01/2008 | YES
A1      | 01/01/2009 | YES

A2      | 01/01/2001 | NO
A2      | 01/01/2002 | NO
A2      | 01/01/2003 | YES
A2      | 01/01/2004 | NO
A2      | 01/01/2005 | YES
A2      | 01/01/2006 | YES

A3      | 01/01/2001 | NO

           ...etc...

该列表是按时间顺序排序的,除了降序/升序之外,我无法对其进行排序。

我无法排序是|否,找到First()或Last(),因为这不会给我所需的值。

我希望能够在每个客户的所有“未计算”之后返回第一个“是”。

在上面的Client [A1]示例中,第7行是我要返回的记录(2007年1月1日)。

客户[A2] - 第5行(01/01/2005)..等等

我的代码如下

var query = 
(
    from m in db.MyTable
    where m.Criteria == XYZ
    select new
    {
      Client = m.Client,
      Date = m.Date, 
      YESorNO = m.YESorNO
    }
).OrderBy(x => x.Date);

使用.FirstOrDefault(x => x.YesOrNO == "YES")返回第3条记录。

User @RenéVogt建议

var result = query.AsEnumerable()
                  .TakeWhile(x => x.YESorNO == "YES")
                  .LastOrDefault();

会完成工作而且确实如此,但我忘了添加查询将返回许多客户端,我需要每个客户端的第一个“是”,因此上述代码是不够的。

迭代我的结果将耗费大量时间,虽然这是一个解决方案,我宁愿这个逻辑在数据库查询本身内(如果可能的话)

非常感谢

2 个答案:

答案 0 :(得分:3)

您需要做的是按client进行分组,然后从末尾开始查找每个的最后YES 。这样的事情(ClientListList<>,您可能需要根据数据的位置进行更改):

var query = ClientList.OrderBy(x => x.client).ThenBy(x => x.date).GroupBy(x => x.client);
foreach (var client in query)
{
    var lastYES=client.Reverse().TakeWhile(x => x.YESorNO == "YES")
              .LastOrDefault();
    Console.WriteLine(String.Format("{0} {1}",client.Key,lastYES.date));
}
//Output: A1 01/01/2007 0:00:00
//        A2 01/01/2005 0:00:00

修改

Mansur Anorboev正确地建议按降序排序,因此无需Reverse,因此代码将是:

var query = ClientList.OrderBy(x => x.client).ThenByDescending(x => x.date).GroupBy(x => x.client);
foreach (var client in query)
{
    var lastYES=client.TakeWhile(x => x.YESorNO == "YES")
              .LastOrDefault();
    Console.WriteLine(String.Format("{0} {1}",client.Key,lastYES.date));
}

修改2

我仍然对我的解决方案不满意,因为它正在使用foreach。这可以在一个Linq命令中完成所有操作:

var query = ClientList.OrderBy(x => x.client)
                      .ThenByDescending(x => x.date)
                      .GroupBy(x => x.client, (key, g) => g.TakeWhile(x => x.YESorNO == "YES").LastOrDefault())
                      .ToList();

这将返回一个列表,其中每个客户端包含一个元素并且日期正确。

答案 1 :(得分:1)

我可以提供一点sql查询

;WITH cte AS (
    SELECT *, ROW_NUMBER() OVER (ORDER BY Client DESC) AS rn  
    FROM [dbo].[tblSkaterhaz]
)
,gte AS (
    SELECT Client,max(rn) mx FROM cte 
    WHERE YesOrNo = 'NO'  
    GROUP BY Client 
)
SELECT cte.* FROM gte
INNER JOIN cte on cte.Client = gte.Client and cte.rn = gte.mx + 1

虽然它不是必需的解决方案,但它产生了所需的结果。您可以创建存储过程并在代码中使用它。

注意:这是根据上面提到的相同表格(和数据)进行测试的

我希望这会对你有所帮助。