C# 根据条件返回特定记录(2)
我以前问过这个问题,但遗漏了问题的一个关键部分 以这个结果列表为例C# 根据条件返回特定记录(2),c#,sql,linq,C#,Sql,Linq,我以前问过这个问题,但遗漏了问题的一个关键部分 以这个结果列表为例 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
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...
列表是按时间顺序排列的,我不能排序,这是降序/升序以外的任何其他方式
我无法对Yes | NO进行排序并找到第一个()或最后一个(),因为这不会给我所需的值
我希望能够在每个客户的所有“否”都计算完毕后返回第一个“是”。
在上面的客户机[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”)
返回第三条记录
用户@RenéVogt建议
var result = query.AsEnumerable()
.TakeWhile(x => x.YESorNO == "YES")
.LastOrDefault();
将完成任务,但我忘了添加查询将返回多个客户机,并且我需要每个客户机的第一个“是”,因此上面的代码不够
迭代我的结果将非常耗时,虽然这是一个解决方案,但我更希望这种逻辑在数据库查询本身中(如果可能的话)
非常感谢您需要做的是按
客户端进行分组
,然后从末尾开始查找每个的最后一个是。类似于此(ClientList
是一个列表
,您可能需要根据数据的位置对其进行更改):
编辑
曼苏尔·阿诺博耶夫(Mansur Anorboev)正确地建议按降序日期进行订购,从而消除了反向订购的需要,因此代码为:
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();
这将返回一个列表,其中每个客户端有一个元素和正确的日期。您需要做的是按client
分组,然后从末尾开始查找每个的最后一个YES
。类似于此(ClientList
是一个列表
,您可能需要根据数据的位置对其进行更改):
编辑
曼苏尔·阿诺博耶夫(Mansur Anorboev)正确地建议按降序日期进行订购,从而消除了反向订购的需要,因此代码为:
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();
这将返回一个列表,每个客户端有一个元素,并且日期正确。我可以提供一些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
虽然这不是所需的解决方案,但它会产生所需的结果。您可以创建一个存储过程并在代码中使用它
注:这是根据上述问题中提到的相同表格(和数据)进行测试的
我希望这将对您有所帮助。我可以提供一些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
虽然这不是所需的解决方案,但它会产生所需的结果。您可以创建一个存储过程并在代码中使用它
注:这是根据上述问题中提到的相同表格(和数据)进行测试的
我希望这将对您有所帮助。您可以通过两个查询轻松完成。抓取每个客户的所有“否”的列表。。。仅为每个客户端选择最后一个否。然后用它来查询最后一个“否”之后的第一个“是”的列表,只需两次查询即可轻松完成。抓取每个客户的所有“否”的列表。。。仅为每个客户端选择最后一个否。然后用它来按日期询问最后一个“否”之后的第一个“是”的列表。很好的解决方案。我认为最好使用降序(x=>x.date)并删除reverse(),因为@MansurAnorboev完全正确。答案编辑现在我看到了OP链接的第一个问题,这似乎不是很原创,因为@RenéVogt接受的答案就是这样。但是,GroupBy
客户机部分可能是OP所需要的,所以我将留下这个答案。我认为最好使用降序(x=>x.date)并删除reverse(),因为@MansurAnorboev完全正确。答案编辑现在我看到了OP链接的第一个问题,这似乎不是很原创,因为@RenéVogt接受的答案就是这样。但是,GroupBy
客户机部分可能是OP需要的,所以我留下这个答案