Linq 将子查询关联到多个列上的相同 table
Linq correlated subquery to same table on multiple columns
我已经查看了与相关子查询相关的其他几个问题,但我仍然不清楚如何完成我需要的。我正在使用 Entity Framework 和 C#,并且有一个名为 STEWARDSHIP 的 table,包含以下列:
- STEWARDSHIP_ID(主键)
- SITE_ID
- VISIT_DATE
- VISIT_TYPE_ID
我需要确定 SITE_ID、VISIT_DATE、VISIT_TYPE_ID 的相同组合不止一次存在的情况,因为它可能代表最终用户错误地输入了重复条目,然后我需要报告这些条目的详细信息。在 SQL 中,我将通过加入 GROUP BY/HAVING 的临时结果来做到这一点,如下所示:
SELECT * FROM stewardship AS s2,
(SELECT site_id, visit_type_id, CAST(visit_date AS DATE) AS visit_date
FROM stewardship
GROUP BY site_id, visit_type_id, CAST(visit_date AS DATE)
HAVING COUNT(*) > 1) AS s
WHERE s2.site_id = s.site_id
AND s2.visit_type_id = s.visit_type_id
AND CAST(s2.visit_date AS DATE) = s.visit_date
在 Linq 中完成此任务的最佳方法是什么?
它与您已有的非常相似。
from s in context.stewardships
group s by new {s.site_id, s.visit_type_id, visit_date} into g
where g.Count() > 1
select g;
这将为您提供具有相似价值观的管理团队。您可以 "flatten" 之后使用 SelectMany 获得这些结果,但您可能会发现它们对于分组处理更有用。
请注意,您可能需要使用 SqlFunctions 或其他工具来执行与日期转换等效的操作。
由于您对 应该 性能更高的不同方法持开放态度,这里是新的 SQL 来实现我认为您想要的。
select distinct s1.*
from stewardship s1
inner join stewardship s2 on
s1.stewardship_id <> s2.stewardship_id and
s1.site_id = s2.site_id and
s1.visit_type_id = s2.visit_type_id and
cast(s1.visit_date as date) = cast(s2.visit_date as date)
order by s1.site_id, s1.visit_type_id
现在,要将其转换为 LINQ,您可以使用以下语句。
var duplicates = (
from s in Stewardships
join s2 in Stewardships
on new { s.Site_id, s.Visit_type_id, s.Visit_date.Date } equals new { s2.Site_id, s2.Visit_type_id, s2.Visit_date.Date }
where s.Stewardship_id != s2.Stewardship_id
select s)
.Distinct()
.OrderBy(s => s.Site_id)
.ThenBy(s => s.Visit_type_id)
请注意,除了等值连接之外,您不能使用任何表达式连接,因此我不得不将非等值连接(通过 PK 确保我们的匹配项不在同一记录上)放在 where 表达式中。您也可以通过 Except() 扩展方法使用 lambda 来完成此操作。
顺序是为了结果的可读性并匹配上面的 SQL 语句。
希望对您有所帮助!
我已经查看了与相关子查询相关的其他几个问题,但我仍然不清楚如何完成我需要的。我正在使用 Entity Framework 和 C#,并且有一个名为 STEWARDSHIP 的 table,包含以下列:
- STEWARDSHIP_ID(主键)
- SITE_ID
- VISIT_DATE
- VISIT_TYPE_ID
我需要确定 SITE_ID、VISIT_DATE、VISIT_TYPE_ID 的相同组合不止一次存在的情况,因为它可能代表最终用户错误地输入了重复条目,然后我需要报告这些条目的详细信息。在 SQL 中,我将通过加入 GROUP BY/HAVING 的临时结果来做到这一点,如下所示:
SELECT * FROM stewardship AS s2,
(SELECT site_id, visit_type_id, CAST(visit_date AS DATE) AS visit_date
FROM stewardship
GROUP BY site_id, visit_type_id, CAST(visit_date AS DATE)
HAVING COUNT(*) > 1) AS s
WHERE s2.site_id = s.site_id
AND s2.visit_type_id = s.visit_type_id
AND CAST(s2.visit_date AS DATE) = s.visit_date
在 Linq 中完成此任务的最佳方法是什么?
它与您已有的非常相似。
from s in context.stewardships
group s by new {s.site_id, s.visit_type_id, visit_date} into g
where g.Count() > 1
select g;
这将为您提供具有相似价值观的管理团队。您可以 "flatten" 之后使用 SelectMany 获得这些结果,但您可能会发现它们对于分组处理更有用。
请注意,您可能需要使用 SqlFunctions 或其他工具来执行与日期转换等效的操作。
由于您对 应该 性能更高的不同方法持开放态度,这里是新的 SQL 来实现我认为您想要的。
select distinct s1.*
from stewardship s1
inner join stewardship s2 on
s1.stewardship_id <> s2.stewardship_id and
s1.site_id = s2.site_id and
s1.visit_type_id = s2.visit_type_id and
cast(s1.visit_date as date) = cast(s2.visit_date as date)
order by s1.site_id, s1.visit_type_id
现在,要将其转换为 LINQ,您可以使用以下语句。
var duplicates = (
from s in Stewardships
join s2 in Stewardships
on new { s.Site_id, s.Visit_type_id, s.Visit_date.Date } equals new { s2.Site_id, s2.Visit_type_id, s2.Visit_date.Date }
where s.Stewardship_id != s2.Stewardship_id
select s)
.Distinct()
.OrderBy(s => s.Site_id)
.ThenBy(s => s.Visit_type_id)
请注意,除了等值连接之外,您不能使用任何表达式连接,因此我不得不将非等值连接(通过 PK 确保我们的匹配项不在同一记录上)放在 where 表达式中。您也可以通过 Except() 扩展方法使用 lambda 来完成此操作。
顺序是为了结果的可读性并匹配上面的 SQL 语句。
希望对您有所帮助!