2017-02-16 68 views
1

我試圖編寫一個簡單的函數,這將允許我得到基於列的值的總和。SQL創建一個函數來獲得基於列名的總和

CREATE FUNCTION [GetSumOfColumnByCase](@column varchar(50), @case int) 
    RETURNS INT 
AS 
BEGIN 

    declare @return int 
    set @return = SUM(CASE WHEN @column = @case THEN 1 ELSE 0 END) 

    -- Return the result of the function 
    return @return 

END 
GO 

我調用這個函數是這樣的:

 SELECT HouseDescription, 
       [dbo].[GetSumOfColumnByCase]([HouseTypeId], 1) AS "houseType1", 
       [dbo].[GetSumOfColumnByCase]([HouseTypeId], 2) AS "houseType2" 

這樣做,讓迫使我GROUP BY兩個houseDescription和HouseTypeId列,但我只是想GROUP BY的housedescription。

如果我做的事情是這樣的:

SELECT HouseDescription, 
     SUM(CASE WHEN HouseTypeId = 1 THEN 1 ELSE 0 END) AS "houseType1", 
     SUM(CASE WHEN HouseTypeId = 2 THEN 1 ELSE 0 END) AS "houseType2" 

其優良的,它不強迫我GROUP BY HouseTypeId。

任何人都可以解釋爲什麼這是?

+0

你基本上不能在SQL Server中做到這一點。要處理變量列,您需要動態SQL。一個函數不能輕易運行動態SQL。 –

回答

2

當您使用GROUP BY子句時,每列需要位於GROUP BY中,或者需要聚合。

在第二個示例中,您正在滿足這些要求 - 將SUM放在函數調用的周圍。在第一個示例中,由於函數調用本身並未包含在聚合中(SUMMAX,MIN等),所以您必須將它放在GROUP BY子句中才能觸發錯誤。

https://msdn.microsoft.com/en-us/library/ms177673.aspx

我與戈登同意雖然,你可能要重新考慮你的這個策略。

+0

這就是答案。 SUM在函數中,而不在主查詢中。 –

+0

@John Thompson,謝謝John對此做了很多有意義的探討,並重新將我的函數改爲只使用case語句並在函數調用之前放置聚合。完美的作品。 –

0

因爲SQL Server在函數中不支持動態SQL(很容易),所以你不能對函數做你想做的事情。要處理任何列,您需要動態SQL。

但是,反正你不需要。如果要在原始數據的每一行上添加總和,則需要窗口函數:

SELECT SUM(CASE WHEN HouseTypeId = 1 THEN 1 ELSE 0 END) OVER() AS houseType1, 
     SUM(CASE WHEN HouseTypeId = 2 THEN 1 ELSE 0 END) OVER() AS houseType2 
. . . 

此查詢不需要聚合。

+0

仔細觀察功能。我不認爲這是答案。他並不想在一個函數中做動態sql。他傳遞的是價值,而不是欄目名稱。使用'@ column'作爲參數名稱具有欺騙性。 –

+0

@Gordon Linoff謝謝戈登,這是一個有趣的話題。約翰斯的回答幫助我重寫了我的功能,以便我不需要按HouseTypeId進行分組。 –

+0

@TabAlleman。 。 。該代碼表示​​「@column = @ case」,並且該示例似乎想要執行windows功能。 –