Linqer не может преобразовать: ошибка синтаксиса SQL: каждое выражение GROUP BY должно содержать хотя бы одну ссылку на столбец

У меня есть этот запрос:

SELECT DISTINCT
       b.NAME AS [Service Name],
       CASE
           WHEN [a].[PAY_MODE_ID] IN ( 1, 2 ) THEN
               'OFFLINE'
           ELSE
               'ONLINE'
       END AS [Transaction Type],
       p.NAME AS [Payment Method],
       SUM(a.REQUESTED_QTY) AS [Transaction],
       SUM(a.ITEM_TOTAL) AS Income
FROM dbo.BILL_INFO_DETAIL AS a
    INNER JOIN dbo.SERVICE_INFO AS b
        ON a.SERVICE_CODE = b.SERVICE_CODE
    INNER JOIN dbo.PAY_MODE AS p
        ON a.PAY_MODE_ID = p.PAY_MODE_ID
WHERE (a.INPUT_STATUS = '1')
      AND (b.SERVICE_CODE IN ( 1610, 1611, 1612 ))
      AND (CONVERT(VARCHAR(2), a.STAMP_DATE, 101) IN ( '10', '11', '12' ))
      AND (CONVERT(VARCHAR(4), a.STAMP_DATE, 102) IN ( '2017' ))
      AND (b.FEE > 1)
GROUP BY b.NAME,
         CASE
             WHEN [a].[PAY_MODE_ID] IN ( 1, 2 ) THEN
                 'OFFLINE'
             ELSE
                 'ONLINE'
         END,
         p.NAME
ORDER BY [Transaction Type];

Linqer не может преобразовать это в правильный LINQ:

Ошибка синтаксиса SQL: каждое выражение GROUP BY должно содержать хотя бы одну ссылку на столбец.

Этот запрос работает в SQL Server. Есть указатели?

Замечания:

  • Удаление DISTINCT не имеет никакого эффекта
  • Удаление ORDER BY не имеет никакого эффекта
  • Удаление ; не имеет никакого эффекта

2 ответа

Решение

Кажется, что все, что мне нужно было сделать, это удалить CASE с PAY_MODE_ID. Я изменил запрос отдельно от этого изменения, чтобы сделать его готовым к работе:

SELECT si.SERVICE_CODE,     
       si.NAME AS [ServiceName],
       bid.PAY_MODE_ID AS [PaymentId],
       p.NAME AS [PaymentName],
       SUM(bid.REQUESTED_QTY) AS [Transaction],
       SUM(bid.ITEM_TOTAL) AS [Income]
FROM BILL_INFO_DETAIL AS bid
    INNER JOIN dbo.SERVICE_INFO AS si
        ON bid.SERVICE_CODE = si.SERVICE_CODE
    INNER JOIN dbo.PAY_MODE AS p
        ON bid.PAY_MODE_ID = p.PAY_MODE_ID
WHERE (bid.INPUT_STATUS = '1')
      AND (si.SERVICE_CODE IN ( 1610, 1611, 1612 ))
      AND (CONVERT(VARCHAR(2), bid.STAMP_DATE, 101) IN ( '10', '11', '12' ))
      AND (CONVERT(VARCHAR(4), bid.STAMP_DATE, 102) IN ( '2017' ))
      AND (si.FEE > 1)
GROUP BY si.SERVICE_CODE,
         si.NAME,   
         bid.PAY_MODE_ID,
         p.NAME

Это привело к LINQ (слегка изменено):

    from bid in db.BILL_INFO_DETAIL
    where
      bid.INPUT_STATUS == true &&
      (new int[] {1610, 1611, 1612 }).Contains(bid.SERVICE_INFO.SERVICE_CODE) &&
      (new int[] {10, 11, 12 }).Contains(bid.STAMP_DATE.Value.Month) &&
      bid.STAMP_DATE.Value.Year == 2017 &&
      bid.SERVICE_INFO.FEE > 1
    group new {bid.SERVICE_INFO, bid, bid.PAY_MODE} by new {
      bid.SERVICE_INFO.SERVICE_CODE,
      bid.SERVICE_INFO.NAME,
      bid.PAY_MODE_ID,
      Column1 = bid.PAY_MODE.NAME
    } into g
    select new {
      g.Key.SERVICE_CODE,
      ServiceName = g.Key.NAME,
      PaymentId = g.Key.PAY_MODE_ID,
      PaymentName = g.Key.NAME,
      Transaction = (int?)g.Sum(p => p.bid.REQUESTED_QTY),
      Income = (decimal?)g.Sum(p => p.bid.ITEM_TOTAL)
    }

Для перевода SQL в понимание запросов LINQ:

  1. Переведите FROM Подвыбирает как отдельно объявленные переменные.
  2. Переводите каждое предложение в порядок предложений LINQ, переводя монадические и агрегатные операторы (DISTINCT, TOP, MIN, MAX и т. д.) в функции, применяемые ко всему запросу LINQ.
  3. Используйте псевдонимы таблиц в качестве переменных диапазона. Используйте псевдонимы столбцов в качестве имен полей анонимного типа.
  4. Используйте анонимные типы (new {... }) для нескольких столбцов.
  5. JOIN условия, которые не все тесты на равенство с AND должен быть обработан с помощью where пункты вне объединения или с перекрестным произведением (from... from...) а потом where
  6. JOIN условия, которые являются множественными ANDТесты на равенство между двумя таблицами должны быть переведены в анонимные объекты
  7. LEFT JOIN моделируется с помощью into присоединяйся и делай из другогоfrom присоединяемая переменная с последующим.DefaultIfEmpty(),
  8. замещать COALESCE с условным оператором (?:) иnullтестовое задание.
  9. Переведите IN в .Contains()а такжеNOT INв!...Contains(), используя буквенные массивы или переменные массива для константных списков.
  10. ПеревестихBETWEEN низкийAND по убыванию <= Икс && Икс <= высокий
  11. Переведите CASE троичному условному оператору ?:,
  12. SELECT * должен быть заменен на select range_variable или для соединений анонимный объект, содержащий все переменные диапазона.
  13. SELECT поля должны быть заменены на select new {... } создание анонимного объекта со всеми нужными полями или выражениями.
  14. правильный FULL OUTER JOIN должен обрабатываться методом расширения.

Так что по вашему запросу,

var ans = (from a in dbo.BILL_INFO_DETAIL
           join b in dbo.SERVICE_INFO on a.SERVICE_CODE equals b.SERVICE_CODE
           join p in dbo.PAY_MODE on a.PAY_MODE_ID equals p.PAY_MODE_ID
           where (a.INPUT_STATUS == "1") &&
                 (new[] { 1610, 1611, 1612 }.Contains(b.SERVICE_CODE)) &&
                 (new[] { 10, 11, 12 }.Contains(a.STAMP_DATE.Month)) &&
                 (new[] { 2017 }.Contains(a.STAMP_DATE.Year)) &&
                 (b.FEE > 1)
           let TransactionType = new[] { 1, 2 }.Contains(a.PAY_MODE_ID) ? "OFFLINE" : "ONLINE"
           group new { a, b, p } by new { bName = b.NAME, TransactionType, pName = p.NAME } into abpg
           orderby abpg.Key.TransactionType
           select new {
               Service_Name = abpg.Key.bName,
               TransactionType = abpg.Key.TransactionType,
               Payment_Method = abpg.Key.pName,
               Transaction = abpg.Sum(abp => abp.a.REQUESTED_QTY),
               Income = abpg.Sum(abp => abp.a.ITEM_TOTAL)
           }).Distinct();
Другие вопросы по тегам