我正在建立一个包含数据库的单元测试框架。
细节并不重要,但是这个前提使我陷入了一些不寻常的情况。
现在,我正在尝试为某些特定的单元测试数据创建视图,并且正在尝试:
CREATE VIEW [foo] AS SELECT * FROM TableValueUDF ( TableValueParam )
(附带说明:将UDF逻辑移到视图本身中,将导致跨数十个数据库对象(如果不是数百个)的大量代码重复,这就是我避免这样做的原因。)
这里明显的问题是,您不能将变量传递到视图中。
但是单元测试数据在技术上是静态的...所以我恢复为:
CREATE VIEW [foo] AS SELECT * FROM TableValueUDF ( ( SELECT * FROM ( VALUES ... ) ) )
...最终用户开发人员可以在其中为每个测试视图手动定义所需的单元测试。
当然,SQL Server对此非常不满意。 (以下代码中指示的错误消息。)
但是我以前从未遇到过这种情况,而且我也不知道如何重新排列该查询以完成我要尝试执行的操作。
(在这种情况下,CROSS APPLY
会有所帮助吗?我不太了解交叉申请。)
我的实际代码比这更大,更复杂,所以我一直在用一个简单的示例场景进行测试,以帮助隔离问题。
自然,错误消息没有任何意义。 (显示在代码中)
谷歌搜索这些错误消息会产生完全不同的情况,在这里无济于事。
示例UDT和UDF定义:
/* Table-value UDT */
CREATE TYPE [dbo].[IntNameList]
AS TABLE
(
[Value] INT NOT NULL ,
[NameText] NVARCHAR ( 48 ) NOT NULL
)
GO
/* Table-value UDF with table-value parameter */
CREATE FUNCTION [dbo].[ProcessData]
(
@tableValueParam [IntNameList] READONLY
)
RETURNS TABLE AS RETURN
(
SELECT
[Value] ,
[NameText] ,
/* Simple example calculation: Is [Value] odd or even? */
CAST ( IIF ( [Value] % 2 <> 0 , 1 , 0 ) AS BIT )
AS [ValueOdd]
FROM @tableValueParam
)
GO
使用声明的变量进行测试,以确保UDF可以按预期运行:
DECLARE @param [IntNameList]
INSERT INTO @param VALUES
( /* Value */ 110 ,
/* NameText */ N'Steve'
) ,
( /* Value */ 111 ,
/* NameText */ N'Mason'
) ,
( /* Value */ 112 ,
/* NameText */ N'Kimberly'
)
/* Works as expected */
SELECT * FROM [dbo].[ProcessData] ( @param )
GO
使用CREATE VIEW
进行测试,这是我正在尝试实现的实际方案:
/* Errors:
1) "Only one expression can be specified in the select list
when the subquery is not introduced with EXISTS."
2) "Operand type clash: int is incompatible with IntNameList"
*/
CREATE VIEW [dbo].[ProcessExampleData] AS
SELECT * FROM [dbo].[ProcessData] ( ( SELECT * FROM ( VALUES
( /* Value */ 110 ,
/* NameText */ N'Steve'
) ,
( /* Value */ 111 ,
/* NameText */ N'Mason'
) ,
( /* Value */ 112 ,
/* NameText */ N'Kimberly'
)
) AS [ExampleData] ( [Value] ,
[NameText] ) ) )