【问题标题】:left join with up to one row in the right table in LINQ在 LINQ 的右表中左连接最多一行
【发布时间】:2020-04-27 03:54:37
【问题描述】:

朋友们,我有一张客户表和一张关系表,用于保存我发送调查链接的客户。同一调查可能已多次发送给同一客户。或者,一些客户可能没有发送任何调查链接。我的目标是带所有客户一次,如果其中一些客户已收到调查问卷,我只想带创建日期最大的那个。记录数必须等于客户数。我写了查询,但是很难翻译 linq 或。你能帮忙吗?

这是查询我写的内容

SELECT *
FROM dbo.Customer c
 LEFT JOIN dbo.SurveyCustomers sc ON sc.SurveyCustomerId =
(
SELECT A.SurveyCustomerId
FROM
(
    SELECT TOP 1 *
    FROM dbo.SurveyCustomers sc1
    WHERE sc1.STATUS = 1
          AND sc1.IsActive = 1
          AND sc1.CustomerId = c.CustomerId
          AND sc1.SurveyId = 1207
          AND sc1.STATUS = 1
          AND sc1.IsActive = 1
    ORDER BY sc1.CreatedDate DESC
) A
)
WHERE c.IsActive = 1
  AND c.STATUS = 1;

客户表

CREATE TABLE [dbo].[Customer](
[CustomerId] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[CustomerTitle] [varchar](500) NOT NULL,
[CustomerEmail] [varchar](500) NOT NULL,
[CreatedDate] [datetime] NOT NULL,
[UpdatedDate] [datetime] NOT NULL,
[IsActive] [bit] NOT NULL,
[Status] [bit] NOT NULL)

SurveyCustomer

CREATE TABLE [dbo].[SurveyCustomers](
[SurveyCustomerId] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[SurveyId] [int] NOT NULL FOREIGN KEY,
[CustomerId] [int] NOT NULL FOREIGN KEY,
[GuidId] [varchar](500) NOT NULL,
[CreatedDate] [datetime] NOT NULL,
[UpdatedDate] [datetime] NOT NULL,
[Status] [bit] NOT NULL,
[IsActive] [bit] NOT NULL)

【问题讨论】:

    标签: c# sql sql-server linq sql-to-linq-conversion


    【解决方案1】:

    对于这种情况,您需要 GROUP BY 子句:

    SELECT c.SurveyCustomerId, MAX( /* THE MAX YOU WANT TO GET */)
    FROM dbo.Customer c
     LEFT JOIN dbo.SurveyCustomers sc ON sc.SurveyCustomerId = A.SurveyCustomerId
    GROUP BY c.SurveyCustomerId
    WHERE c.IsActive = 1 AND c.STATUS = 1 /*AND OTHER CONDITIONS */;
    

    进一步阅读 GROUP BY 条款:

    https://docs.microsoft.com/en-us/sql/t-sql/queries/select-group-by-transact-sql?view=sql-server-ver15

    更新:抱歉错过了 LINQ 部分:您应该可以这样做:

    public class SurveyCustomer
        {
            public int SurveyCustomerId { get; set; }
    
            public virtual ICollection<Survey> Surveys { get; set; }
        }
    
        public class Survey
        {
            public int SurveyId { get; set; }
        }
    
        public class SurveyCustomerReadModel
        {
            public int SurveyCustomerId { get; set; }
    
            public int LastSurveyId { get; set; }
        }
    
        public class SurveyCustomerRepository
        {
            public List<SurveyCustomer> SurveyCustomers { get; set; }
    
            public IEnumerable<SurveyCustomerReadModel> GetSurveyCustomerReadModel()
            {
                return this.SurveyCustomers
                    .Select(sc => new SurveyCustomerReadModel
                    {
                        SurveyCustomerId = sc.SurveyCustomerId,
                        LastSurveyId = sc.Surveys.Max(/* SOME CRITERIA FOR DEFINING THE MAX*/).SurveyId
                    });
            }
        }
    

    问候!

    【讨论】:

    • 我也编辑了这个问题。非常遗憾。我忘记了
    【解决方案2】:

    你可以这样做:

    var finalSurveyCustomers = from customer in Customers
                               join sc in SurveyCustomers on customer.CustomerId equals sc.SurveyCustomerId into leftCustomers
                               from leftCustomer in leftCustomers.DefaultIfEmpty()
                               select new { LeftId = customer.Id, SurveyId = leftCustomer ?? 0 }; // can use int.Max or int.Min
    

    【讨论】:

    • 我的兄弟我已经编辑了这个问题。我很抱歉。
    【解决方案3】:

    您可以使用OUTER APPLY 来获得相同的结果。

    SELECT *
    FROM dbo.Customer c
     OUTER APPLY 
    (
        SELECT TOP 1 *
        FROM dbo.SurveyCustomers sc1
        WHERE sc1.STATUS = 1
              AND sc1.IsActive = 1
              AND sc1.CustomerId = c.CustomerId
              AND sc1.SurveyId = 1207
        ORDER BY sc1.CreatedDate DESC
    ) A
    WHERE c.IsActive = 1
      AND c.STATUS = 1;
    

    和 linq 等价物:

    Customers.SelectMany(c => SurveyCustomers
                            .Where(sc1 => 
                                sc1.Status == true 
                                && sc1.IsActive == true
                                && sc1.CustomerId == c.CustomerId
                                && sc1.SurveyId == 1207 )
                            .OrderByDescending(sc1 => sc1.CreatedDate)
                            .Take(1).DefaultIfEmpty(), 
                        (c, sc) => new { c, sc })
    .ToList()
    

    【讨论】:

    • 谢谢兄弟,我以前从未使用过外部应用。我非常喜欢它。但是 linq 等效项在 where 子句中出现错误
    • 你能写出异常信息吗?
    • 我更改了 SurveyCustomers -> entity.SurveyCustomers。现在没问题。我会立即尝试并接受答案。 Çok teşekkür ederim:)
    • 我试过 sql 工作得很好,就像我想要的那样。但是 linq 部分没有带来正确的空记录。
    • 非常感谢。这正是我想要的。我接受答案。如果您愿意,也可以将问题向上调。
    猜你喜欢
    • 2018-01-21
    • 1970-01-01
    • 1970-01-01
    • 2015-07-27
    • 1970-01-01
    • 1970-01-01
    • 2011-01-17
    • 2020-07-28
    相关资源
    最近更新 更多