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:
- Переведите
FROM
Подвыбирает как отдельно объявленные переменные. - Переводите каждое предложение в порядок предложений LINQ, переводя монадические и агрегатные операторы (
DISTINCT
,TOP
,MIN
,MAX
и т. д.) в функции, применяемые ко всему запросу LINQ. - Используйте псевдонимы таблиц в качестве переменных диапазона. Используйте псевдонимы столбцов в качестве имен полей анонимного типа.
- Используйте анонимные типы (
new {
...}
) для нескольких столбцов. JOIN
условия, которые не все тесты на равенство сAND
должен быть обработан с помощьюwhere
пункты вне объединения или с перекрестным произведением (from
...from
...) а потомwhere
JOIN
условия, которые являются множественнымиAND
Тесты на равенство между двумя таблицами должны быть переведены в анонимные объектыLEFT JOIN
моделируется с помощьюinto
присоединяйся и делай из другогоfrom
присоединяемая переменная с последующим.DefaultIfEmpty()
,- замещать
COALESCE
с условным оператором (?:
) иnull
тестовое задание. - Переведите
IN
в.Contains()
а такжеNOT IN
в!
...Contains()
, используя буквенные массивы или переменные массива для константных списков. - Перевестих
BETWEEN
низкийAND
по убыванию<=
Икс&&
Икс<=
высокий - Переведите
CASE
троичному условному оператору?:
, SELECT *
должен быть заменен на select range_variable или для соединений анонимный объект, содержащий все переменные диапазона.SELECT
поля должны быть заменены наselect new {
...}
создание анонимного объекта со всеми нужными полями или выражениями.- правильный
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();