如何将以下 SQL 语句转换为 LINQ 方法语法

Posted

技术标签:

【中文标题】如何将以下 SQL 语句转换为 LINQ 方法语法【英文标题】:How to convert the following SQL statement to LINQ Method Syntax 【发布时间】:2021-06-29 18:23:31 【问题描述】:

我正在使用 EF6 将以下 SQL 语句转换为 LINQ 寻求帮助。我花了似乎永远在寻找不同的例子,但没有找到任何有效的方法。我看过 linqer(那里没有成功)我看过 linqpad(它不会将 sql 转换为 linq)

下面的查询以 SQL 格式返回我正在寻找的内容,目标是使用 Group 的 WHERE 子句基于内部分组(使用分组作为 DISTINCT 查询)返回表的所有列将记录集过滤为所需的内容,并加入 [CdrCallId] 上的内部分组仅返回 [CdrCallId] 匹配的记录。

SELECT ct1.StartTime, ct1.CdrCallID, ct1.CallingNumberId, ct1.CalledNumberId, ct1.ThreadSequence
FROM CallTransactions as ct1
join (select CdrCallID
      from CallTransactions as ct2 
      WHERE [StartTime] >= '10/1/2020 00:00:00 AM' AND [StartTime] <= '03/31/2021 00:00:00 AM' AND [CalledNumberId] = '1670589' OR [CallingNumberId] = '1670589' OR [DestinationNumberId] = '1670589' OR [TransferringNumberId] = '1670589' OR [KeyPartyNumberId] = '1670589'
      group by ct2.CdrCallID) ct2
on ct1.CdrCallID = ct2.CdrCallID
StartTime CdrCallID CallingNumberId CalledNumberId ThreadSequence
2020-11-02 12:49:34.007 995368-307-63751883929019 1670589 1658625 995368
2021-02-19 14:38:54.600 78900-050-63751893781085 1670589 1658625 78900
2020-10-27 09:58:15.007 704239-301-63751883392147 1663834 1667952 704239
2020-10-27 09:58:15.007 704239-301-63751883392147 1663834 1670589 704239
2020-10-27 09:57:14.007 704239-301-63751883392147 1663834 1667952 704239
2020-10-27 09:57:59.000 704239-301-63751883392147 1663834 1670589 704239
2020-11-02 10:15:06.007 497923-307-63751883688115 1663847 1670589 497923

我一直在努力寻找合适的 LINQ 方法语法来模仿上述查询。

【问题讨论】:

我不相信 SQL 会返回您需要的内容(可能在您尝试的较小子集上)。您确定所有这些 AND、OR 吗?您能否提供一些数据和所需的输出 【参考方案1】:

我认为你的 SQL 有一些缺陷,实际上应该是这样的:

SELECT ct1.StartTime, ct1.CdrCallID, ct1.CallingNumberId, ct1.CalledNumberId, ct1.ThreadSequence 
FROM CallTransactions as ct1 
where exists 
(select *
    from CallTransactions as ct2 
     WHERE ct1.CdrCallID = ct2.CdrCallID and 
            (([StartTime] >= '20201001' AND [StartTime] <= '20210331') AND 
           ([CalledNumberId] = '1670589' OR 
           [CallingNumberId] = '1670589' OR 
           [DestinationNumberId] = '1670589' OR 
           [TransferringNumberId] = '1670589' OR 
           [KeyPartyNumberId] = '1670589'));

在 Linq 中会是这样的:

var start = new DateTime(2020,10,1);
var end = new DateTime(2021,4,1);
var numberId = "1670589";
var callIDs = ctx.CallTransactions
    .Where(x => x.StartTime >= start && x.StartTime < end && 
        (x.CalledNumberId == numberId ||
         x.CallingNumberId == numberId ||
         x.DestinationNumberId == numberId ||
         x.TransferringNumberId == numberId ||
         x.KeyPartNumberId == numberId))
    .Select(x => x.CdrCallId);

var result = ctx.CallTransactions.Where(x => callIDs.Any(ci => ci.CdrCallId == x.CdrCallId)
   .Select(ct1 => new ct1.StartTime, ct1.CdrCallID, ct1.CallingNumberId, ct1.CalledNumberId, ct1.ThreadSequence);

PS:您实际上并不需要将所有内容都转换为 EF Linq。您也可以从 Linq 调用原始 SQL。

【讨论】:

非常感谢您的及时回复,我为我的可怕格式问题向大家道歉,这是我第一次在这里发帖,我需要学习你们都使用的所有很酷的技巧...... .【参考方案2】:
IQueryable<CallTransactions> items;
var start=new DateTime(2021,1,10);
var due=new DateTime(2021,3,31);

var result=items.Where(a=>a.StartTime>=start && a.StartTime<=due)
                .Where(a=>a.CalledNumberId = '1670589' || 
                          a.CallingNumberId = 1670589 || 
                          a.DestinationNumberId = 1670589 || 
                          a.TransferringNumberId = 1670589 ||
                          a.KeyPartyNumberId = '1670589')
                .Select(a=>new 
                    a.StartTime, 
                    a.CdrCallID, 
                    a.CallingNumberId, 
                    a.CalledNumberId, 
                    a.ThreadSequence
                );

我认为这不是必需的连接,一旦您过滤了集合,您就会拥有所有必需的行。

【讨论】:

以上是关于如何将以下 SQL 语句转换为 LINQ 方法语法的主要内容,如果未能解决你的问题,请参考以下文章

将 SQL 语句转换为 LINQ VS2010

将SQL语句转换为LINQ VS2010

如何将此 GROUP BY / MIN SQL 查询转换为 LINQ?

如何将 SQL 中的多个内部联接转换为 LINQ?

将包含 where、group by、sum 和必须的 MySQL 语句转换为 Linq to Sql

如何将以下 linq 查询转换为 SQL 中的 (Having)