我有一个与各种关键字相关的参数代码列表。我想将其存储/维护为存在缺席矩阵/表,其中每列代表一个关键字,每行都是一个参数。 Y/(null) 将指示每个关键字对每个参数的适用性,如下所示:
参数 | A | B | C | D | E | F | G | H |
---|---|---|---|---|---|---|---|---|
12345 | 是 | 是 | ||||||
23456 | 是 | 是 | 是 | |||||
78912 | 是 | 是 | ||||||
78187 | 是 | 是 | ||||||
89473 | 是 | 是 | ||||||
73292 | 是 | 是 | 是 | |||||
52891 | 是 | 是 | 是 | |||||
80636 | 是 | 是 | ||||||
47350 | 是 | 是 | ||||||
29450 | 是 | 是 | 是 |
但是,为了便于查询端使用,我想将其(动态地作为计算表或列)转换为仅包含每个参数的适用关键字的字符串,如下所示:
参数 | 关键词 |
---|---|
12345 | C、F |
23456 | C、F、G |
78912 | A、H、 |
78187 | A、H、 |
89473 | C、D |
73292 | C、E、G |
52891 | C、E、G |
80636 | B、H、 |
47350 | C、E |
29450 | C、F、G |
如果可能,此汇总列可以存储为计算列,作为上表的一部分。另外,我需要它在列数方面是动态的,因为它需要将除原始参数列之外的所有列转换为后一种形式。
我不知道什么可能对此有用。我的技术还没那么强。
好吧,你需要在这里做两件事。首先,您需要以一种格式获取数据,在该格式中您可以将所有这些任意列视为单个列来处理。基本上,你想要一张有
param
、columnname
、value
的桌子。
棘手的部分是,由于您事先不知道列名,因此必须使用动态 sql(基本上构建一个作为文字代码执行的字符串。如果您不这样做,这是一种危险的事情不知道你在用它做什么。如果你打算修改它或在其他地方使用它,请确保你了解“注入攻击”的漏洞。
要获取要“逆透视”的列列表,我们将从元数据表中选择它们
sys.columns
。请注意,由于我使用的是临时表,因此我引用的是 tempdb.sys.columns
。如果您的数据位于其他地方,请相应地更改数据库(或者仅在脚本顶部设置 Use {mydb}
语句)。
这是设置数据:
drop table if exists #table
select *
into #Table
from
(
select Param = 12345, A = 0, B = 0, C = 1, D = 0, E = 0, F = 1, G = 0, H =0 union all
select 23456, 0, 0, 1, 0, 0, 1, 1, 0 union all
select 78912, 1, 0, 0, 0, 0, 0, 0, 1 union all
select 78187, 1, 0, 0, 0, 0, 0, 0, 1 union all
select 89473, 0, 0, 1, 1, 0, 0, 0, 0 union all
select 73292, 0, 0, 1, 0, 1, 0, 1, 0 union all
select 82891, 0, 0, 1, 0, 1, 0, 1, 0 union all
select 80636, 0, 1, 0, 0, 0, 0, 0, 1 union all
select 47350, 0, 0, 1, 0, 1, 0, 0, 0 union all
select 29450, 0, 0, 1, 0, 0, 1, 1, 0
) a
这是表中的列列表。注意
quotename
的使用。这会转义任何方括号并将值括在方括号中。尽管您不太可能拥有包含可注入代码的列名称,但如果您有一个包含空格的列,这也会使您安全。所以不管怎样用起来都很好。
declare @Columns nvarchar(max)
select @Columns = string_agg(quotename(name), ',')
from tempdb.sys.columns
where object_id = object_id('tempdb.dbo.#table')
and name != 'Param'
-- Here's what we generated above
select @Columns
现在是时候构建我们的枢轴了。我们在这里做三件事:
对数据进行逆透视以获取格式为
param, value, name
的数据,其中 value
是列的位值,name
是我们要连接的列名称
我们仅将数据过滤到
value
为 1(即“Y”或 True)的行,因为这些是我们要连接的值。
我们按
Param
进行分组,并再次使用 string_agg
来形成具有位值 1 的每一行。
声明 @SQL nvarchar(max) = concat
('
在组内选择 Param, string_agg(Name, '','') (按名称排序)
来自#table
unpivot((', @Columns, ') 中的名称值) u
其中值 = 1
按参数分组
')
选择@sql
执行 sp_executesql @sql
注意 我对最后一条语句的格式感到抱歉;我不知道为什么它没有格式化为代码。