Проблема у Вас есть то, что вы сортировки по имени строки месяц, поэтому вполне естественно, что он должен следуйте буквенному порядку, если вы хотите его в хронологическом порядке, вам нужно отсортировать по месячному номеру (DATEPART(MONTH, tDate)
), что просто означает добавить это к GROUP BY
, чтобы вы могли сортировать по нему. Это не повлияет на мощность, так как любое заданное имя месяца может содержать только один месяц.
При этом не следует использовать назначение переменной для объединения строк, it is not guaranteed to return the correct results, не говоря уже о порядке выполнения вами. Фактический результат, который вы закончите, будет зависеть от внутренних путей, предпринятых оптимизатором. Вместо этого используйте FOR XML PATH()
.
DECLARE @start DATETIME = '2016-08-03 00:00',
@end DATETIME = '2016-11-08 00:00',
@day VARCHAR(MAX) = '';
SET @day = STUFF((SELECT ',[' + LEFT(DATENAME(MONTH, tDate), 3) + ']'
FROM someDB.[dbo].[someTable]
WHERE tdate BETWEEN @start AND @end
GROUP BY LEFT(DATENAME(MONTH, tDate), 3), DATEPART(MONTH, tDate)
ORDER BY DATEPART(MONTH, tDate)
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '');
SELECT @day;
Стоит отметить, что вы не можете получить результаты, которые вы хотите, если диапазон дат занимает несколько лет, и это личные предпочтения, но я склонен держаться подальше от BETWEEN
для диапазонов дат for reasons set out here
Если вы собираетесь строить и выполнять динамический SQL, как это, я бы advise you use sp_executesql
, так что вы можете передать ваши параметры с соответствующими типами, вместо того, чтобы сделать эту ужасную конкатенацию, чтобы применить фильтры даты:
'+''''+ convert(varchar,@start) +''' and '
вместо этого вы можете просто декларируют и проходят paramters:
DECLARE @query NVARCHAR(MAX) = 'SELECT ... WHERE tDate BETWEEN @start AND @end';
EXECUTE sp_executesql @Query, N'@Start DATETIME, @end DATETIME', @Start, @end;
NB You should always specify a length when converting to, or declaring a varchar
Наконец, при работе с DATETIME
буквального формат даты xxxx-xx-xx
является неоднозначным, это может означать как yyyy-MM-dd
и yyyy-dd-MM
, поэтому в зависимости от в региональных настройках ваш начальный параметр может быть как 3 августа, так и 8 марта. Только Формат инварианта культуры для DATETIME
is yyyyMMdd
. Для получения дополнительной чтения см Bad habits to kick : mis-handling date/range queries
Таким образом, ваш полный запрос может выглядеть примерно так:
DECLARE @start DATETIME = '20160803 00:00',
@end DATETIME = '20161108 00:00',
@day VARCHAR(MAX) = '';
SET @day = STUFF((SELECT ',[' + LEFT(DATENAME(MONTH, tDate), 3) + ']'
FROM someDB.[dbo].[someTable]
WHERE tdate BETWEEN @start AND @end
GROUP BY LEFT(DATENAME(MONTH, tDate), 3), DATEPART(MONTH, tDate)
ORDER BY DATEPART(MONTH, tDate)
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '');
DECLARE @Query NVARCHAR(MAX) =
'SELECT *
FROM (SELECT Customer, LEFT(DATENAME(MONTH,tdate), 3) AS OrderMonth, SUM(saleAmount) AS Amount
FROM SomeDB.[dbo].[SomeTable]
WHERE tdate >= @start
AND tDate <= @end
GROUP BY Customer, LEFT(DATENAME(MONTH,tdate), 3)) AS pp
PIVOT (SUM(Amount) FOR OrderMonth IN (' + @day + ')) AS pvt';
EXECUTE sp_executesql @Query, N'@Start DATETIME, @end DATETIME', @Start, @end;
Я не ставил, чтобы связать так много статей Аарона бертрановских, просто так получилось, что вы попали в много ловушек, о которых он писал в блогах. Таким образом, хотя я могу закончить ссылку на full list of his "Bad Habits to Kick" articles, они заслуживают внимания.
Благодарим за быстрый ответ. Цель состоит в том, чтобы иметь столбец «Ряд клиентов» и столбец «Месяцы». Лет нет и проблема. Это будет выглядеть Ян февраля Cust A 500 200 Каст B 200 300 –
Я извиняюсь, что мой вопрос не был завершен. Я добавил остальную часть кода, если это может быть любая помощь. Заранее спасибо. –
Удивительные объяснения. Вопрос, который у меня есть, - DateKey? Что это такое. У меня просто красное подчеркивание для этого. –