2016-11-29 95 views
0

編輯:我列出的代碼我想排序在SQL Server中的陣列按月份

其餘的陣列看起來像[八月],[月],[月],[月]。

我希望這是動態的,以便始終按照正確的月份順序進行查詢。

這是我正在使用的代碼。

ALTER PROCEDURE [dbo].[CustomerFlowByMonth] 
@start datetime, 
@end datetime 

as 
declare @day varchar(max) = '' 
select @day = @day +','+'['+CONVERT(varchar(3),DATENAME(MONTH,tdate))+']' 
FROM someDB.[dbo].[someTable] 
Where tdate between @start and @end 
group by DATENAME(MONTH,tdate) 
order by DATENAME(MONTH,tdate) 
set @day = substring(@day, 2, (len(@day))) 

--select @day 
declare @query varchar(max) = 
' 
select * 
from 
(
SELECT Customer, CONVERT(varchar(3),DATENAME(MONTH,tdate)) AS OrderMonth 
,SUM(saleAmount) as amount 
    FROM someDB.[dbo].[SomeTable] 
    Where tdate between '+''''+ convert(varchar,@start) +''' and '''+convert(varchar,@end) +''' 
    group by Customer, CONVERT(varchar(3),DATENAME(MONTH,tdate)) 
) as pp 
--order by Customer, DATENAME(MONTH,tdate) 
pivot (sum(amount) for OrderMonth in ('[email protected]+')) as total' 

--print @query 
execute (@query) 

我不是最好的,在SQL Server,以便任何幫助,將不勝感激

回答

0

您遇到的問題是,你是用字符串月份名稱排序,所以很自然的,它應該按照字母順序排列,如果您需要按時間順序排列,則需要按月份編號(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; 

值得注意的是,你可能不會得到你想要的結果,如果您的日期範圍跨越多個年了,這是個人喜好,但我傾向於的日期範圍for reasons set out here

避開BETWEEN如果你要建立並執行動態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-ddyyyy-dd-MM,使視區域設置您的起始參數可以是8月3日和3月8日。 只有文化不變格式DATETIMEyyyyMMdd。更多閱讀見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來完成它們,但它們非常值得一讀。

+0

感謝您的快速回復。 我們的目標是擁有一列客戶,以及一列月份。 年是不是和問題。 它看起來像 Jan Feb Cust A 500 200 Cust B 200 300 –

+0

我很抱歉我的問題沒有完成。如果可以提供幫助,我添加了其餘的代碼。提前致謝。 –

+0

令人驚歎的解釋。我遇到的問題是DateKey?這是什麼代表。我只是有紅色的下劃線。 –

0

您的問題是

order by CONVERT(varchar(3),DATENAME(MONTH,tdate)) 

此訂單將訂購字母順序每月的日期。 (如四月前)的日期本身

而是爲了

order by tdate 
0

您的解決方案應該是

ORDER BY MONTH(tDate) 

MONTH (Transact-SQL)

返回一個整數表示的月份指定的日期。