不,不可能通过引用传递查询表达式而不是通过值传递(您尝试使用的语法完全不受支持)。所以,如果这是你的问题的要点,那么答案是没有。
但请允许我添加一些其他建议,告诉您如何才能和/或应该完成您希望完成的任务。
首先,创建或引用对象时请always use the schema prefix。
CREATE TYPE dbo.IndexValue AS TABLE (Id int, Value VARCHAR(max));
接下来,使用内联表值函数,而不是多语句表值函数,使用SCHEMABINDING
和always specify a length for variable-length types like nvarchar
(虽然不知道为什么你在函数中使用nvarchar
当因为是不可能的输入):虽然我不得不怀疑
DECLARE @x dbo.IndexValue;
INSERT @x VALUES(1,'hoobah'),(1,'floobah'),(2,'a'),(2,'x'),(2,'y'),(3,'me');
SELECT Id, Names FROM dbo.GetConcatenatedWithKeyAsInt32(@x);
疗法:
CREATE FUNCTION dbo.GetConcatenatedWithKeyAsInt32
(
@Values dbo.IndexValue READONLY
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN (SELECT
[Id],
[Names] = stuff((
select ', ' + CAST(Id AS nvarchar(255)) as [text()]
from @Values AS xt
where xt.Id = t.Id
for xml path('')
), 1, 2, '')
FROM @Values AS t GROUP BY t.Id);
GO
现在你可以使用这个功能没问题e是函数中的另一个逻辑错误,那就是您应该将XML操作应用于值列,而不是ID。这个输出是:
Id Names
---- -------
1 1,1
2 2,2,2
3 3
如果这是你真正的意思做,则函数应该有进一步的变化,最明显的是纠正输入来自不安全的实体处理,并保护数据XML(例如>
)。
ALTER FUNCTION dbo.GetConcatenatedWithKeyAsInt32
(
@Values dbo.IndexValue READONLY
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN (SELECT
[Id],
[Names] = stuff((
select ', ' + Value
from @Values AS xt
where xt.Id = t.Id
for xml path(''), TYPE
).value('.[1]','varchar(max)'), 1, 2, '')
FROM @Values AS t GROUP BY t.Id);
GO
现在这个工程好得多:
DECLARE @x dbo.IndexValue;
INSERT @x VALUES(1,'hoo&bah'),(1,'floo<b>ah'),(2,'a'),(2,'x'),(2,'y'),(3,'me');
SELECT Id, Names FROM dbo.GetConcatenatedWithKeyAsInt32(@x);
输出:
Id Names
---- ------------------
1 hoo&bah, floo<b>ah
2 a, x, y
3 me
至于错误信息,@Lamak是正确的,你不能传递一个查询到的参数函数,你需要在查询中包含函数调用,例如使用CROSS APPLY或OUTER APPLY。
至于更新后的代码示例,您正试图开始工作,我不知道为什么要使用此功能。为什么不干脆:
SELECT DISTINCT c.Id, Names = STUFF((SELECT ', ' + a.City
FROM dbo.Addresses AS a
WHERE a.CustomerId = c.Id GROUP BY a.City
FOR XML PATH(''), TYPE
).value('.[1]','varchar(max)'), 1, 2, '')
FROM dbo.Customers AS c;
如果你想使通用的,那么我想你可以恢复到你的低效多语句TVF。下面是语法来做到这一点:
CREATE FUNCTION dbo.GetConcatenatedWithKeyAsInt32_b
(
@Values dbo.IndexValue READONLY
)
RETURNS @ret TABLE
(
Id int PRIMARY KEY NOT NULL,
value nvarchar(max) NOT NULL
)
WITH SCHEMABINDING
AS
BEGIN
INSERT @ret SELECT
Id, Names = STUFF((SELECT ', ' + Value
FROM @Values AS xt
WHERE xt.Id = t.Id GROUP BY Value
FOR XML PATH(''), TYPE
).value('.[1]','varchar(max)'), 1, 2, '')
FROM @Values AS t GROUP BY t.id;
RETURN;
END
GO
然后,你可以把它 - 再次,既然你想要的通用表类型作为输入 - 馅的加入到申报表变量后的结果。有没有办法只是将您的SQL查询传递给函数,对不起。你需要传递一个表格,而不是查询。
DECLARE @x dbo.IndexValue;
INSERT @x(Id, Value)
SELECT c.Id, a.City
FROM dbo.Addresses AS a
INNER JOIN dbo.Customers AS c
ON a.CustomerId = c.Id;
SELECT * INTO #x FROM dbo.GetConcatenatedWithKeyAsInt32_b(@x);
除了混淆掉XML的逻辑,这并不能真正获得你什么,可能极大地降低了该查询。你似乎经历了很多额外的层,没有明显的原因(将连接的结果插入到表类型中,然后使用表类型来调用函数,然后将这些行插入函数内的声明表中,然后对该表执行XML操作)。
不要看执行计划,看看哪一个“更快” - 它分配各种近似成本,不知道如何正确评估和计算某些XML操作的成本。相反,只需要时间!
SET NOCOUNT ON;
SELECT GETUTCDATE();
GO
SELECT c.Id, Names = STUFF((SELECT ', ' + a.City
FROM dbo.Addresses AS a
WHERE a.CustomerId = c.Id GROUP BY a.City
FOR XML PATH(''), TYPE
).value('.[1]','varchar(max)'), 1, 2, '')
INTO #x
FROM dbo.Customers AS c;
DROP TABLE #x;
GO 5000
SELECT GETUTCDATE();
GO
DECLARE @x dbo.IndexValue;
INSERT @x(Id, Value)
SELECT c.Id, a.City
FROM dbo.Addresses AS a
INNER JOIN dbo.Customers AS c
ON a.CustomerId = c.Id;
SELECT * INTO #x FROM dbo.GetConcatenatedWithKeyAsInt32_b(@x);
DROP TABLE #x;
GO 5000
SELECT GETUTCDATE();
GO
结果:
XML: 16,780 ms
Your approach: 32,230 ms
即使我改:
INSERT @x(Id, Value)
SELECT c.Id, a.City
要:
INSERT @x(Id, Value)
SELECT DISTINCT c.Id, a.City
(这样函数具有较少的数据处理,如果有重复的),我只刮了一点时间FF(你仍然需要GROUP BY
在功能方面,恕我直言,以保护自己免受将喂它查询):
XML: 16,824 ms
Your approach: 29,576 ms
我没有做的东西,当我告诉你,DRY并不总是有益的SQL服务器。函数不仅仅是指针,它们还有大量的开销。
我希望[这些搜索结果]有一些(https://www.google.com/search?q=sql+call+user+defined+function&oq=sql+call+user+de&aqs=chrome.1.69i57j0l5。 2627j0j8&sourceid = chrome&espv = 210&es_sm = 93&ie = UTF-8)有帮助 –
@AndersonGreen谷歌搜索显然是我做的第一件事。 – John