2012-07-02 171 views
3

我有一個返回兩列的TVF:「措施」(名稱)和「分數」,分數值該措施:樞軸表值函數

dbo.ScoringFunction(param1, param2, ..., paramN) 
Measure Score 
------- ----- 
measure1 10 
measure2 5 
...  ... 
measureN 15 

我跑這個功能針對大量的行包含其參數:

Name Param1 Param2 ... ParamN 
---- ------ ------   ------ 
Daniel 12  5    6 
etc. 

我試圖找到一種方式來顯示的措施和他們的分數旁邊的參數確定這些分數:

Name Param1 Param2 ... ParamN measure1 measure2 ... measureN 
---- ------ ------   ------ -------- --------   -------- 
Daniel 12  5    6  10   5    15 
etc. 

到目前爲止,我已經嘗試過使用數據透視表,但這很棘手,因爲數據被旋轉包含在TVF而不是靜態表中。我也嘗試過使用CROSS APPLY,但是一旦我獲得了數據(度量&分數),我仍然無法將它轉換爲格式良好的行。

如果有人有任何想法,他們將不勝感激!

+0

在什麼地方TVF獲取其數據?也許你可以向我們展示源數據,幾行樣本數據和期望的結果。 TVF很可能是一個不必要的障礙,但這裏沒有足夠的細節供任何人肯定地說。 –

+0

所以你用一堆INT值調用'dbo.ScoringFunction'?因此,從第二個記錄集中,您可以獲取參數列並將它們的值發送到函數中,並獲取您想要樞軸轉出的一些行?有多少測量行出來? 'PIVOT'不能生成動態數量的列。 –

+0

@JeremyPridemore它大約有15個左右的措施(不要記得手,但它是一個固定的數字,他們有固定的名字)。 –

回答

0

不改變太多(希望),我會做旋轉在功能,然後使用CROSS功能APPLY和拉列。所以,如果你的函數是這樣的:

CREATE FUNCTION dbo.ScoringFunction (parameters) 
RETURNS TABLE 
RETURN (

SELECT Measure, Score 
FROM … 

) 

,那麼我會改寫這樣的:

CREATE FUNCTION dbo.ScoringFunction (parameters) 
RETURNS TABLE 
RETURN (

WITH originalSelect AS ( 
    SELECT Measure, Score 
    FROM … 
) SELECT measure1, measure2, … FROM originalSelect PIVOT ( MAX(Score) FOR Measure IN (measure1, measure2, …) ) p 

) 

,並在這樣最終的查詢使用它:

SELECT 
    t.Name, 
    t.param1, 
    t.param2, 
    … 
    x.measure1, 
    x.measure2, 
    … 
FROM atable t 
CROSS APPLY dbo.ScoringFunction (t.param1, t.param2, …) x 
+0

在您的最終查詢中,您可以執行'... FROM atable t CROSS APPLY dbo.ScoringFunction(t.param1,t.param2,.. )'。沒有必要把它放在子查詢中。 –

+0

啊是的,我絕對不必要地複雜,謝謝。 –

0

如果您看起來像這樣的功能:

CREATE FUNCTION [dbo].[fGetSpecificMeasures] 
(
    @HeightScore INT 
    , @WeightScore INT 
    , @TvScore INT 
) 
RETURNS TABLE 
RETURN 
(
    SELECT 
     Final.Height AS tv_height_score 
     , Final.[Weight] AS tv_weight_score 
     , Final.TV AS tv_score 
    FROM 
    (
     SELECT measure, score FROM ScoringRubric WHERE measure = 'Height' AND @HeightScore BETWEEN bottom_of_range AND top_of_range 
      UNION ALL 
     SELECT measure, score FROM ScoringRubric WHERE measure = 'Weight' AND @WeightScore BETWEEN bottom_of_range AND top_of_range 
      UNION ALL 
     SELECT measure, score FROM ScoringRubric WHERE measure = 'TV' AND @TvScore BETWEEN bottom_of_range AND top_of_range 
    ) Base 
    PIVOT 
    (
     MAX(score) 
     FOR measure 
     IN 
     (
      [Height] 
      , [Weight] 
      , [TV] 
     ) 
    ) Final 
); 
GO 

而一個看起來是這樣的:

CREATE FUNCTION [dbo].[fGetMeasureScore] 
(
    @Measure VARCHAR(50) 
    , @Value INT 
) 
RETURNS TABLE 
RETURN 
(
    SELECT 
     score 
    FROM ScoringRubric 
    WHERE measure = @Measure 
     AND @Value BETWEEN bottom_of_range AND top_of_range 
); 
GO 

然後,您可以用以下任一讓您的數據

DECLARE @User VARCHAR(50) = 'Daniel' 

SELECT 
    UserProfile.* 
    , HeightScore.score AS tv_height_score 
    , WeightScore.score AS tv_weight_score 
    , TvScore.score AS tv_score 
FROM UserProfile 
INNER JOIN ScoringRubric HeightScore 
    ON HeightScore.measure = 'Height' 
    AND UserProfile.height BETWEEN HeightScore.bottom_of_range AND HeightScore.top_of_range 
INNER JOIN ScoringRubric WeightScore 
    ON WeightScore.measure = 'Weight' 
    AND UserProfile.[weight] BETWEEN WeightScore.bottom_of_range AND WeightScore.top_of_range 
INNER JOIN ScoringRubric TvScore 
    ON TvScore.measure = 'TV' 
    AND UserProfile.TV BETWEEN TvScore.bottom_of_range AND TvScore.top_of_range 
WHERE UserProfile.name = @User 

SELECT 
    * 
FROM UserProfile 
CROSS APPLY dbo.fGetSpecificMeasures(height, [weight], TV) 
WHERE name = @User 

SELECT 
    UP.* 
    , HeightScore.score AS tv_height_score 
    , WeightScore.score AS tv_weight_score 
    , TvScore.score AS tv_score 
FROM UserProfile UP 
CROSS APPLY fGetMeasureScore('Height', UP.height) HeightScore 
CROSS APPLY fGetMeasureScore('Weight', UP.[weight]) WeightScore 
CROSS APPLY fGetMeasureScore('TV', UP.TV) TvScore 
WHERE UP.name = @User 

我真的不知道哪一個你會找到最適合你的用途。如果您有任何問題,請告訴我。

至於你原來的問題,如果是這樣的功能:

CREATE FUNCTION [dbo].[fGetMeasureScoresOriginal] 
(
    @HeightScore INT 
    , @WeightScore INT 
    , @TvScore INT 
) 
RETURNS TABLE 
RETURN 
(
    SELECT measure, score FROM ScoringRubric WHERE measure = 'Height' AND @HeightScore BETWEEN bottom_of_range AND top_of_range 
     UNION ALL 
    SELECT measure, score FROM ScoringRubric WHERE measure = 'Weight' AND @WeightScore BETWEEN bottom_of_range AND top_of_range 
     UNION ALL 
    SELECT measure, score FROM ScoringRubric WHERE measure = 'TV' AND @TvScore BETWEEN bottom_of_range AND top_of_range 
) 
GO 

然後,你可以寫像這樣的查詢和數據透視:

SELECT 
    Final.name 
    , Final.OriginalHeight AS height 
    , Final.OriginalWeight AS [weight] 
    , Final.OriginalTv AS TV 
    , Final.Height AS tv_height_score 
    , Final.[Weight] AS tv_weight_score 
    , Final.TV AS tv_score 
FROM 
(
    SELECT 
     UP.name 
     , UP.height AS OriginalHeight 
     , UP.[weight] AS OriginalWeight 
     , UP.TV AS OriginalTv 
     , Measures.measure 
     , Measures.score 
    FROM UserProfile UP 
    CROSS APPLY dbo.fGetMeasureScoresOriginal(UP.height, UP.[weight], UP.TV) Measures 
    WHERE UP.name = @User 
) Base 
PIVOT 
(
    MAX(score) 
    FOR measure 
    IN 
    (
     [Height] 
     , [Weight] 
     , [TV] 
    ) 
) Final 

編輯:剛剛意識到我沒有」回答原來的問題。現在添加。

0

如果您想旋轉一組靜態行,您可以使用我所描述的技術here

重新發布這個例子,所以它會是不同的表格,但是這個技術可以應用在你的案例中。

SELECT 
    Customers.CustID, 
    MAX(CASE WHEN CF.FieldID = 1 THEN CF.FieldValue ELSE NULL END) AS Field1, 
    MAX(CASE WHEN CF.FieldID = 2 THEN CF.FieldValue ELSE NULL END) AS Field2, 
    MAX(CASE WHEN CF.FieldID = 3 THEN CF.FieldValue ELSE NULL END) AS Field3, 
    MAX(CASE WHEN CF.FieldID = 4 THEN CF.FieldValue ELSE NULL END) AS Field4 
    -- Add more... 

    FROM Customers 

    LEFT OUTER JOIN CustomFields CF 
    ON CF.ID = Customers.CustID 

    WHERE Customers.CustName like 'C%' 

    GROUP BY Customers.CustID