SQL Server UDF 数组输入和输出
Posted
技术标签:
【中文标题】SQL Server UDF 数组输入和输出【英文标题】:SQL Server UDF array inputs and outputs 【发布时间】:2016-08-03 19:00:05 【问题描述】:我有一组 CODE_1-10 列,其中包含诊断代码。我想创建一组变量 CODE_GROUP_1-17,它们指示某些特定诊断代码集中的一个是否与任何 CODE_1-10 变量匹配。例如,如果 CODE_1-10 中的任何一个匹配“123”或“456”,则 CODE_GROUP_1 = 1,如果 CODE_1-10 中的任何一个匹配“789”、“111”、“333”、“444”或“,则 CODE_GROUP_2 = 1富”。
这是一个使用值构造函数的示例。
CASE WHEN (SELECT count(value.val)
FROM (VALUES (CODE_1)
, (CODE_2)
, (CODE_3)
, (CODE_4)
, (CODE_5)
, (CODE_6)
, (CODE_7)
, (CODE_8)
, (CODE_9)
, (CODE_10)
) AS value(val)
WHERE value.val in ('123', '456')
) > 0 THEN 1 ELSE 0 END AS CODE_GROUP_1,
CASE WHEN (SELECT count(value.val)
FROM (VALUES (CODE_1)
, (CODE_2)
, (CODE_3)
, (CODE_4)
, (CODE_5)
, (CODE_6)
, (CODE_7)
, (CODE_8)
, (CODE_9)
, (CODE_10)
) AS value(val)
WHERE value.val in ('789','111','333','444','foo')
) > 0 THEN 1 ELSE 0 END AS CODE_GROUP_2
我想知道是否还有另一种更有效的方法。有没有办法制作一个接受 CODE_1-10 数组并输出一组列 CODE_GROUP_1-17 的 CLR UDF?
【问题讨论】:
SQL Server 中没有数组这样的东西。您是否考虑过表值参数 (TVP)?您可以从应用程序(例如 DataTable)中传入结构化数据,而无需进行任何混乱的解构/重建。 如何构建表值参数以包含一个包含 CODE_1-10 的小表,而无需复制粘贴“VALUES(...) ...”17 次不同的时间? 好吧,假设您已经有一个表类型并声明了一个名为@tvp
的局部变量,您可以说:;WITH x AS (SELECT TOP (10) rn = ROW_NUMBER() OVER (ORDER BY number) FROM master.dbo.spt_values) INSERT @tvp(col) SELECT 'CODE_' + RTRIM(rn) FROM x;
如果您想查看它的作用,请在没有 @987654324 的情况下运行它@ 少量。我只提到了 TVP,因为它听起来就像您的值数组应该来自应用程序,并且您在这里对其进行硬编码以进行演示。
我会调查的。我的值数组是一个巨大的表中的列,名为 CODE_1-10。我想将此映射函数应用于每一行,并将结果输出到 select 语句中的列。
【参考方案1】:
你至少可以避免像这样重复FROM (VALUES ...)
:
SELECT
CODE_GROUP_1 = COUNT(DISTINCT CASE WHEN val IN ('123', '456') THEN 1 END),
CODE_GROUP_2 = COUNT(DISTINCT CASE WHEN val IN ('789','111','333','444','foo') THEN 1 END),
...
FROM
(
VALUES
(CODE_1),
(CODE_2),
(CODE_3),
(CODE_4),
(CODE_5),
(CODE_6),
(CODE_7),
(CODE_8),
(CODE_9),
(CODE_10)
) AS value(val)
如果CODE_1
、CODE_2
等是列名,则可以在CROSS APPLY中将上述查询作为派生表使用:
SELECT
...
FROM
dbo.atable -- table containing CODE_1, CODE_2 etc.
CROSS APPLY
(
SELECT ... -- the above query
) AS x
;
【讨论】:
这不是我想要做的,而是一个更好的解决方案。谢谢! 顺便说一下,COUNT(DISTIINCT ... ) 这么多次实际上是我的查询时间的两倍多。当我改为使用交叉应用方法但将 COUNT(DISTINCT ...) 替换为 MAX(CASE ... ELSE 0 END) 时,查询时间从 21 分钟变为 30 秒。 @SeanOgden:MAX 确实是一个更好的替代品。我自己多次看到并使用过它,但昨晚我在写这个答案时从未想到过这个想法。谢谢提醒。【参考方案2】:您可以创建 2 个新表,并将列附加为行吗?因此,如果您需要保留 1-10 值和 dx 代码以及您需要的任何关键字段,则一个表将是带有源列的 dxCode,另一个表将是带有 17 个组的 dxGroup,如果您是源 groupID需要它,以及您的目标 dx 值。 然后要确定哪些代码属于哪些组,您可以加入您的 dx 字段。
【讨论】:
如果我理解正确,您的解决方案将需要扩展原始表,每行输入数据最多包含 10 行。关键字段不小,而且很多,而且表很大,所以这个不太理想。 好吧,这个术语是“规范化”,但是是的,如果需要,您将拥有 PK 字段、sourceColumnID 字段以及一个或多个值字段。这个想法是在尝试确定哪些值在哪个集合中之前,将 10 列(或 17 个组)中的每一列中的各个非空值合并。 是的,我知道规范化,我只是不确定你在说什么,因为描述令人困惑。无论如何,就我而言,这个解决方案并不是最好的选择。感谢您的回复! 你试过了吗?这是数据库服务器经过优化以执行的。在大范围内,这是您唯一的选择。在小范围内,保持原样并不重要。以上是关于SQL Server UDF 数组输入和输出的主要内容,如果未能解决你的问题,请参考以下文章