转换为 LINQ - 子查询 Join / where / group by / order by / select

问题描述 投票:0回答:1

我准备的SQL查询如下:

SELECT 
    r.BookingID, r.FlightDate, r.CarrierCode, r.FlightNo, 
    r.InvoiceNumber, SUM(r.Price) total_price
FROM 
    Reservations r
INNER JOIN 
    (SELECT r.BookingID, COUNT(*) cnt
     FROM Reservations r
     GROUP BY r.BookingID) AS all_group ON r.BookingID = all_group.BookingID
LEFT JOIN 
    (SELECT r.BookingID, COUNT(*) cnt
     FROM Reservations r
     WHERE r.InvoiceNumber IS NOT NULL
     GROUP BY r.BookingID) AS not_null_group ON r.BookingID = not_null_group.BookingID
WHERE 
    all_group.cnt = not_null_group.cnt 
    OR r.InvoiceNumber IS NULL
GROUP BY 
    r.BookingID, r.FlightDate, r.CarrierCode, r.FlightNo, r.InvoiceNumber
ORDER BY 
    r.FlightDate, r.CarrierCode, r.FlightNo, r.InvoiceNumber

我想转换为 LINQ,但它对我来说太复杂了。你能指导我吗?

非常感谢...

sql linq
1个回答
0
投票

现有查询的精确翻译将产生以下 LINQ:

from r in Reservations
join all_group in
    (from r in Reservations r
     group by r.BookingID into g
     select new { BookingID: g.Key, cnt = g.Count() })
  on r.BookingID = all_group.BookingID
join not_null_group_joined in 
    (from Reservations r
     where r.InvoiceNumber != null
     group by r.BookingID into g
     select new { BookingID = g.Key, cnt = g.Count() })
  on r.BookingID = not_null_group_joined.BookingID into gj1
  from not_null_group_joined in gj1.DefaultIfEmpty()
where
    all_group.cnt = not_null_group.cnt 
    || r.InvoiceNumber == null
group by
    new { r.BookingID, r.FlightDate, r.CarrierCode, r.FlightNo, r.InvoiceNumber }
    into g
select
    new { g.Key.BookingID, g.Key.FlightDate, g.Key.CarrierCode, g.Key.FlightNo, g.Key.InvoiceNumber,
          total_price: g.Sum(r => r.Price)
        }
order by
    new { g.Key.FlightDate, g.Key.CarrierCode, g.Key.FlightNo, g.Key.InvoiceNumber };

但是,这无论如何都不是很有效。首先,可以使用条件聚合和

HAVING

组合两个子查询
COUNT(*) cnt_all_group, COUNT(InvoiceNumber) cnt_not_null

更好的是,使用窗口函数消除所有这些。

SELECT 
  r.BookingID,
  r.FlightDate,
  r.CarrierCode,
  r.FlightNo, 
  r.InvoiceNumber,
  CASE WHEN SUM(COUNT(*)) OVER (PARTITION BY r.BookingID)
          = SUM(COUNT(InvoiceNumber)) OVER (PARTITION BY r.BookingID)
       THEN SUM(r.price)
       ELSE SUM(CASE WHEN r.InvoiceNumber IS NULL THEN r.price END)
       END AS total_price
FROM Reservations r
GROUP BY 
  r.BookingID,
  r.FlightDate,
  r.CarrierCode,
  r.FlightNo,
  r.InvoiceNumber
ORDER BY 
  r.FlightDate,
  r.CarrierCode,
  r.FlightNo,
  r.InvoiceNumber;

等效的 LINQ 要让它使用窗口函数有点复杂,但类似这样的东西应该可以工作:

from r in Reservations
group by new {
  r.BookingID,
  r.FlightDate,
  r.CarrierCode,
  r.FlightNo,
  r.InvoiceNumber
} into g1
select new {
  g1.BookingID,
  g1.FlightDate,
  g1.CarrierCode,
  g1.FlightNo,
  g1.InvoiceNumber,
  total_price = g1.Sum(r => r.Price),
  null_price = g1.Sum(r => r.InvoiceNumber == null ? r.Price : null),
  all_count = g1.Count(),
  not_null = g1.Count(r => r.InvoiceNumber != null)
}
group by g1.BookingId into g2
from r2 in g2
select new {
  r2.BookingID,
  r2.FlightDate,
  r2.CarrierCode,
  r2.FlightNo,
  r2.InvoiceNumber,
  total_price = g2.Sum(all_count) == g2.Sum(not_null)
    ? r2.total_price
    : r2.null_price
};
© www.soinside.com 2019 - 2024. All rights reserved.