簡體   English   中英

具有多個子查詢的 Linq 查詢

[英]Linq query with multiple subqueries

我正在將 Oracle Sql 查詢轉換為 Linq,但不確定如何繼續。 這是 Sql 查詢:

SELECT *
FROM   CustomerShip,
    (SELECT DISTINCT b.ShipSeq AS shipSeq
     FROM   Orders a,
            CustomerShip b
     WHERE  a.OrderId IN (SELECT OrderId
                          FROM   Orders
                          WHERE  CustomerId = @CustomerId
                          AND    OrderType <> 'A')
     AND    b.CustomerId = @CustomerId
     AND    b.ShipSeq = a.CustShip
     AND    OrderStatus <> 'C'
     GROUP BY b.ShipSeq) i
WHERE  CustomerId = @CustomerId
AND    (Address NOT LIKE '%RETAIL%STORE%')
AND    ShipSeq = i.ShipSeq(+)
ORDER BY ShipTo DESC, OrderDate DESC;

在轉換為 linq 時,我試圖將其分解為三個單獨的查詢。

var query1 = from c in CustomerShip
            where c.CustomerId == customerId
            && !c.Address.Contains("RETAIL")
            && !c.Address.Contains("STORE")
            orderby c.ShipTo descending, c.OrderDate descending
            select c;

var query2 = from o in Orders
         where o.CustomerId == customerId
         && !o.OrderType.Equals("A")
         select o.OrderId;

var query3 = (from o in Orders
         from c in CustomerShip
         where c.CustomerId == customerId
         && c.ShipSeq == o.CustShip
         && !o.OrderStatus.Equals("A")
         select c.ShipSeq).Distinct();

現在我試圖將它們全部組合成一個查詢,但不確定如何去做。 這是我要去的方向:

var query = from c in CustomerShip

let subquery = from o in Orders
               where o.CustomerId == customerId
               && !o.OrderType.Equals("A")
               select o.OrderId

    from or in model.Orders
    where subquery.Contains(or.OrderId) 
    && c.CustomerId == customerId
    && c.ShipSeq == or.CustShip
    && !or.OrderStatus.Equals("A")
    group c by c.ShipSeq
    into i
    select c.ShipSeq

where c.CustomerId == customerId
&& !c.Address.Contains("RETAIL")
&& !c.Address.Contains("STORE")
orderby c.ShipTo descending, c.OrderDate descending 
select c, i;

更新

我有一個類型有效的查詢,但它需要將近兩分鍾來執行(與 Oracle 查詢的 0.02 秒相比)並且結果的順序不正確。 有人看到我缺少什么嗎?

var innerQuery = from x in model.Orders
                    where x.CustomerId == customerId
                    && !x.OrderType.Equals("A")
                    select x.OrderId;

var result = from c in model.CustomerShip
            join subQuery in 
            (
                (from o in model.Orders
                from c in model.CustomerShip 
                where c.CustomerId == customerId
                && innerQuery.Contains(o.OrderId)
                && !o.FLAG_ORD_STATUS.Equals("C")
                && c.ShipSeq == o.CustShip
                select c.ShipSeq).Distinct()

            ) on c.ShipSeq equals subQuery into temp
            from x in temp.DefaultIfEmpty()
            where c.CustomerId == customerId
            && !c.Address.Contains("RETAIL")
            && !c.Address.Contains("STORE")
            orderby c.ShipTo descending, c.OrderDate descending
            select c;

請記住,您只是在此處構建查詢。 在您執行ToList().FirstOrDefault()或其他任何操作之前,不會執行任何操作。 SO,您可以在其他查​​詢中使用這些查詢,並且在執行時會創建一個大 SQL 語句。

var query2 = from o in Orders
             where o.CustomerId == customerId
             && !o.OrderType.Equals("A")
             select o.OrderId;

var query3 = (from o in Orders
              join c in CustomerShip on o.CustShip equals c.ShipSeq 
              where c.CustomerId == customerId
              && !o.OrderStatus.Equals("A")
              && query2.Contains(o.OrderId)
              select c.ShipSeq).Distinct();

var query1 = from c in CustomerShip
             from i in query3
             where c.CustomerId == customerId
             && !c.Address.Contains("RETAIL")
             && !c.Address.Contains("STORE")
             && c.ShipSeq == i.ShipSeq
             orderby c.ShipTo descending, c.OrderDate descending
             select c;

但是,我很確定您可以將 query2 和 query3 減少到僅:

var query3 = (from o in Orders
              join c in CustomerShip on o.CustShip equals c.ShipSeq 
              where c.CustomerId == customerId
              && !o.OrderStatus.Equals("A")
              && !o.OrderType.Equals("A")
              select c.ShipSeq).Distinct();

嘗試這樣的事情。 我為一些類建模只是為了消除錯誤。 如果您按 ShipSeq 分組,則不需要不同。 只需從組中取出第一項就會得到相同的結果。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace ConsoleApplication60
{
    class Program
    {
        static void Main(string[] args)
        {
            int customerID = 1234;
            List<Order> CustomTypeA = Order.orders
                .Where(x => (x.CustomerId == customerID) && (x.OrderType == "A") && (x.OrderStatus == "C")).ToList();

            var results = (from CustA in CustomTypeA 
                          join CustShip in Ship.CustomerShip on CustA.CustomerId equals CustShip.CustomerId 
                          select new { CustA = CustA, CustShip = CustShip})
                          .Where(x => (!RetailStore(x.CustShip.Address)) && (x.CustA.CustShip == x.CustShip.ShipSeq))
                          .OrderByDescending(x => x.CustShip.OrderDate)
                          .GroupBy(x => x.CustShip.ShipSeq)
                          .Select(x => x.FirstOrDefault())
                          .Select(x => new {
                              CustomerID = x.CustShip.CustomerId,
                              Address = x.CustShip.Address,
                              OrderDate = x.CustShip.OrderDate
                          }).ToList();

        }
        static Boolean RetailStore(string address)
        {
            string pattern = "RETAIL.*STORE";
            return Regex.IsMatch(address, pattern);
        }
    }
    public class Order
    {
        public static List<Order> orders = new List<Order>();

        public int CustomerId { get; set; }
        public string OrderType { get; set; }
        public string CustShip { get; set; }
        public string OrderStatus { get; set; } 
    }
    public class Ship
    {
        public static List<Ship> CustomerShip = new List<Ship>();

        public int CustomerId { get; set; }
        public string ShipSeq { get; set; }
        public string Address { get; set; }
        public DateTime OrderDate { get; set; }
     }
}

query2 和 query3 在此處合並為內部查詢

var Innerquery = (from o in Orders
              join c in CustomerShip on o.CustShip equals c.ShipSeq 
              where c.CustomerId == customerId
              && !o.OrderStatus.Equals("A")
              && !o.OrderType.Equals("A")
              select c.ShipSeq).Distinct();

var query1 = from c in CustomerShip
             from i in query3
             where c.CustomerId == customerId
             && innerquery.Contains(c.CustomerId)
             && !c.Address.Contains("RETAIL")
             && !c.Address.Contains("STORE")
             && c.ShipSeq == i.ShipSeq
             orderby c.ShipTo descending, c.OrderDate descending
             select c;

或者你可以試試 Linqer http://www.sqltolinq.com

您的查詢在 EF 中變慢的原因可能有很多 - 我建議使用分析器。

可能的原因是 EF 創建了一個低效的查詢(通常數據庫應該創建它自己的優化,但我在 EF 和 Oracle 方面有過糟糕的經歷),或者,根據它加載的結果數量,將其映射到實際對象非常昂貴.

一般來說,雖然在 .NET 世界中似乎不是一個流行的觀點,但我建議創建一個視圖,或者在有復雜查詢時使用dbcontext.Database.SqlQuery<CustomerShip>(sql) ,尤其是在使用 Oracle 時,至少根據我過去的經驗(已經有一段時間了,所以我可能是錯的。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM