SQL Server:通过基于参数和STUFF使用条件组()
我有一段代码,我想变成一个函数。代码的目的是将某些记录按变量标准分组在一起,并使用STUFF()创建分组连接。我希望能够切换发生组的参数(因此也是STUFF的参数)。SQL Server:通过基于参数和STUFF使用条件组()
但是,以下给出的错误是选择列表中的可选参数(例如下例中的OwnerName)无效,因为它们不包含在聚合函数或GROUP BY子句中。
考虑像下面的一个简单的例子(现实生活中的版本有很多的参数,因此为什么我希望能够得到这些都为一个查询):
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
编辑:如果我改变了下面的内容,那么它似乎会返回正确的连接,除非它是NULL,那么连接本身就是NULL。此外,如果我尝试将值更改为ISNULL(Cars1.OwnerName,'Placeholder')或与COALESCE类似,它会给我出现相同的错误(在上面的select语句中无效)。
AND (@FlagOwnerName = 0 OR Cars2.OwnerName = Cars1.OwnerName)
到
AND CASE WHEN @FlagOwnerName = 1 THEN Cars1.OwnerName = Cars2.OwnerName
根据您的意见,我不认为使用STUFF与FOR XML如果最好的方式来处理这一点。通常,将多行连接成单个字符串的最佳方法是使用递归公用表表达式(CTE)。
有一些使用CTE(和一些替代方法)here的例子。
我已经调整了其中一个CTE选项来执行类似于您所描述的操作。
首先,我已经建立了一个简单的表格,类似于你所描述的数据:然后我用一个CTE是建立一个汽车牌照和值附加的数据集
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');
/按品牌/型号汇总。可变@FlagOwnerName控制是否从CTE或这些值从源表的基本值在最终SELECT语句中使用:
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
注意,在你的评论暗示你不想返回OWNERNAME当@FlagOwnerName = 0,而这是可能的我在存储过程(即,根据参数执行不同的查询)我不会推荐它。最好是返回一组一致的列,如果您在报告顶部使用报告工具,那么您可能会在其中包含一些逻辑以根据参数值隐藏列。
你的意思是你想用CREATE FUNCTION语句创建一个实际的SQL Server函数吗?或者你只是想与你的SELECT语句内联?这也有助于了解您正在使用的SQL Server版本。 – Nathan
不好意思,这将成为重复调用的存储过程的一部分。数据库在SQL Server 2008上。 – am109
我想你可能需要更多地解释你正在尝试做什么 - 你对“LicenseIDs”有什么期望?在XML上使用STUFF函数的目的是什么?你是否期望Cars1与Cars2成为一对多的关系? – Nathan