2017-05-31 19 views
0

私は関数に変換したいコードを用意しています。コードの目的は、特定のレコードを可変基準でグループ化し、STUFF()を使用してグループ化された連結を作成することです。私はグループが発生するパラメータ(したがってSTUFFのパラメータも)を切り替えることができるようにしたいと思います。SQL Server:パラメータとSTUFF()に基づく条件付きグループの使用

ただし、以下の例では、集計関数またはGROUP BY句のいずれにも含まれていないため、オプションのパラメータ(例:下の例のOwnerName)は選択リストでは無効です。

SELECT CarMake, CarModel, CASE WHEN @FlagOwnerName = 1 THEN OwnerName ELSE NULL END AS [OwnerName], SUM(CarValue), 
LicenseIDs = STUFF((SELECT ',' + CONVERT(VARCHAR(20),Cars2.LicenseID) AS [text()] 
    FROM DB.dbo.Cars Cars2 
    WHERE Cars2.CarMake = Cars1.CarMake 
     AND Cars2.CarModel = Cars1.CarModel 
     AND (@FlagOwnerName = 0 OR Cars2.OwnerName = Cars1.OwnerName) 
    FOR XML PATH('')), 1, 1, '') 
FROM DB.dbo.Cars Cars1 
GROUP BY CarMake, 
    CarModel, 
    CASE WHEN @FlagOwnerName = 1 THEN OwnerName ELSE NULL END 

EDIT

は、以下の(現実の生活のバージョンは、なぜ私は1つのクエリにこれらのすべてを取得できるようにしたいため、多くのパラメータを持っている)のような簡単な例を考えてみます。私が以下を変更した場合、NULLの場合を除いて正しい連結を返すと思われますが、連結自体はNULLです。さらに、値をISNULL(Cars1.OwnerName、 'Placeholder')またはCOALESCEと同様に変更しようとすると、同じエラーが表示されます(上記のselect文では無効です)。

AND CASE WHEN @FlagOwnerName = 1 THEN Cars1.OwnerName = Cars2.OwnerName 
+0

CREATE FUNCTIONステートメントを使用して実際のSQL Server関数を作成することを意味しますか?または、SELECT文でインラインで処理したいだけですか?また、使用しているSQL Serverのバージョンを知ることもできます。 – Nathan

+0

申し訳ありませんが、これは繰り返し呼び出されるストアドプロシージャの一部です。データベースはSQL Server 2008上にあります。 – am109

+0

"LicenseIDs"に期待しているデータは何ですか? XMLでSTUFF関数を使用する目的は何ですか?あなたはCars1とCars2が1対多の関係になることを期待していますか? – Nathan

答えて

0

AND (@FlagOwnerName = 0 OR Cars2.OwnerName = Cars1.OwnerName) 

あなたのコメントに基づいて最良の方法はこれに接近した場合、私はXML FORとSTUFFを使用しないと思います。通常、複数の行を1つの文字列に連結する最良の方法は、再帰的な共通表式(CTE)を使用することです。

CTE(いくつかの別の方法)を使用する例がいくつかあります。here

CTEオプションの1つを、あなたが記述したものと似たようなことをするために採用しました。

まず、私はあなたが説明してきたデータに似たシンプルなテーブルを設定している:

create table #cars (CarMake varchar(50), CarModel varchar(50), CarValue INT, OwnerName varchar(50), LicenseID varchar(50)); 

insert into #cars(CarMake, CarModel, CarValue, OwnerName, LicenseID) values ('Toyota','Camry', 12000, 'Steve','ABC123'); 
insert into #cars(CarMake, CarModel, CarValue, OwnerName, LicenseID) values ('Toyota','Camry', 12000, 'Bob','HED999'); 
insert into #cars(CarMake, CarModel, CarValue, OwnerName, LicenseID) values ('Toyota','Camry', 19000, 'Helen','WKS444'); 
insert into #cars(CarMake, CarModel, CarValue, OwnerName, LicenseID) values ('Ford','Mustang',30000, 'Amy','JKJL88'); 
insert into #cars(CarMake, CarModel, CarValue, OwnerName, LicenseID) values ('Ford','Mustang',30000, 'Billy-Bob','EZ1111'); 
insert into #cars(CarMake, CarModel, CarValue, OwnerName, LicenseID) values ('Aston Martin','Vantage',90000, 'Mike','HY7733'); 

私は、車のライセンスと値が/追加されたデータセットを構築するためにCTEを使用しましたmake/modelによって集計されます。ソーステーブルからCTEまたはベース値からこれらの値は、最終的なSELECT文で使用されているかどうかの変数@FlagOwnerNameコントロール:

DECLARE @FlagOwnerName bit = 1; 

WITH cte (CarMake, CarModel, CarValueTotal, Car_Val, LicenseList, License_ID, length_) 
AS 
( 
    SELECT 
     CarMake, CarModel, 0, 0, CAST('' AS VARCHAR(8000)), CAST('' AS VARCHAR(8000)), 0 
    FROM #cars 
    GROUP BY CarMake, CarModel 
    UNION ALL 
    SELECT c.CarMake, c.CarModel, cte.CarValueTotal + c.CarValue, c.CarValue, 
      CAST(cte.LicenseList + CASE WHEN length_ = 0 THEN '' ELSE ', ' END + c.LicenseID AS VARCHAR(8000)), 
      CAST(LicenseID AS VARCHAR(8000)), 
      length_ + 1 
    FROM cte 
    INNER JOIN #cars c ON cte.CarMake = c.CarMake AND cte.CarModel = c.CarModel 
    WHERE c.LicenseID > cte.License_ID 
) 
SELECT 
    cars.CarMake, 
    cars.CarModel, 
    CASE WHEN @FlagOwnerName = 1 THEN cars.OwnerName ELSE 'ALL' END as OwnerName, 
    CASE WHEN @FlagOwnerName = 1 THEN cars.CarValue ELSE totals.CarValueTotal END as CarValue, 
    CASE WHEN @FlagOwnerName = 1 THEN cars.LicenseID ELSE totals.LicenseList END as LicenseID 
FROM #cars cars 
INNER JOIN 
(
    SELECT CarMake, CarModel, LicenseList, CarValueTotal 
    FROM ( 
      SELECT CarMake, CarModel, LicenseList, CarValueTotal, 
      RANK() OVER (PARTITION BY CarMake, CarModel ORDER BY length_ DESC) 
      FROM CTE 
     ) D (CarMake, CarModel, LicenseList, CarValueTotal, rank) 
    WHERE rank = 1 
) totals ON cars.CarMake = totals.CarMake AND cars.CarModel = totals.CarModel 
GROUP BY 
    cars.CarMake, 
    cars.CarModel, 
    CASE WHEN @FlagOwnerName = 1 THEN cars.OwnerName ELSE 'ALL' END, 
    CASE WHEN @FlagOwnerName = 1 THEN cars.CarValue ELSE totals.CarValueTotal END, 
    CASE WHEN @FlagOwnerName = 1 THEN cars.LicenseID ELSE totals.LicenseList END 

ので@FlagOwnerName = 1、我々が得る:

CarMake   CarModel OwnerName CarValue LicenseID 
Aston Martin Vantage  Mike  90000  HY7733 
Ford   Mustang  Amy   30000  JKJL88 
Ford   Mustang  Billy-Bob 30000  EZ1111 
Toyota   Camry  Bob   12000  HED999 
Toyota   Camry  Helen  19000  WKS444 
Toyota   Camry  Steve  12000  ABC123 

そして@FlagOwnerName = 0は、我々が得るとき:

CarMake   CarModel OwnerName CarValue LicenseID 
Aston Martin Vantage  ALL   90000  HY7733 
Ford   Mustang  ALL   60000  EZ1111, JKJL88 
Toyota   Camry  ALL   43000  ABC123, HED999, WKS444 

注意をあなたのコメントにあなたはとき@FlagOwnerName = 0これが可能である私ながらownernameには、返されたくなかった暗黙のことストアドプロシージャ(すなわち、パラメータに基づいて異なるクエリを実行する)私はそれをお勧めしません。一貫性のある一連の列が返されるようにすることをお勧めします。その上にレポートツールを使用する場合は、パラメータ値に基づいて列を非表示にするロジックをいくつか含めることができます。

関連する問題