3

2つの列を返すTVFがあります:'measure'(名前)と'score'、そのメジャーの数値スコア:

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も使用してみましたが、データ(メジャーとスコア)を取得した後でも、適切にフォーマットされた行にピボットすることはできません。

誰かアイデアがあれば、大歓迎です!

4

3 に答える 3

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

編集:私が元の質問に答えなかったことに気づきました。今それを追加します。

于 2012-07-02T23:31:07.390 に答える
0

静的な行のセットをピボットする場合は、ここで説明した手法を使用できます。

例を再投稿すると、テーブルが異なりますが、この手法はあなたの場合にも適用できると思います。

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
于 2012-07-03T06:18:30.970 に答える
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
于 2012-07-03T08:57:38.587 に答える