带演员表的选择中的动态“列”
Posted
技术标签:
【中文标题】带演员表的选择中的动态“列”【英文标题】:Dynamic "column" in select with cast 【发布时间】:2017-08-09 17:04:26 【问题描述】:我正在寻找一种方法来根据另一个 SQL 查询的条件在表中转换数据。
我的表格如下;
数据表: 身份证 |实体 ID |价值1 |价值2 |值 3 ... 值 200
实体: 身份证 |名称
字段: 身份证 |实体 ID |数据类型 |字段编号
查找: 身份证 |实体 ID |字段编号
我的理想输出如下:
数据.Id [Id] Field.Id [FieldId] Entity.Id [EntityId] [StringVal] [间隔]“StringVal”和“IntVal”都将根据“Fields”表中的“DataType”列进行设置,如果设置为“lookup”(在“Data”表中存储为字符串),则应在此选择查询中解析为整数并填充到“IntVal”列中,否则应直接解析为 [StringVal] 列。
我有以下 SQL 查询,它可以按预期工作,但是,如果我有 200 个数据字段,我必须为每个字符串和查找复制 CASE 和 WHEN 子句 200 次,然后就是复杂性添加新类型,例如“DateTime”,这将导致更多问题。
SELECT
dt.Id as [Id],
f.Id as [FieldId],
f.EntityId as [EntityId],
CASE
WHEN f.DataType = 'string' and f.FieldNum = 0 THEN dt.Value0
WHEN f.DataType = 'string' and f.FieldNum = 1 THEN dt.Value1
WHEN f.DataType = 'string' and f.FieldNum = 2 THEN dt.Value2
WHEN f.DataType = 'string' and f.FieldNum = 3 THEN dt.Value3
WHEN f.DataType = 'string' and f.FieldNum = 4 THEN dt.Value4
WHEN f.DataType = 'string' and f.FieldNum = 5 THEN dt.Value5
WHEN f.DataType = 'string' and f.FieldNum = 6 THEN dt.Value6
WHEN f.DataType = 'string' and f.FieldNum = 7 THEN dt.Value7
WHEN f.DataType = 'string' and f.FieldNum = 8 THEN dt.Value8
WHEN f.DataType = 'string' and f.FieldNum = 9 THEN dt.Value9
ELSE NULL
END as [StringVal],
CAST(CASE
WHEN f.DataType = 'lookup' and f.FieldNum = 0 THEN dt.Value0
WHEN f.DataType = 'lookup' and f.FieldNum = 1 THEN dt.Value1
WHEN f.DataType = 'lookup' and f.FieldNum = 2 THEN dt.Value2
WHEN f.DataType = 'lookup' and f.FieldNum = 3 THEN dt.Value3
WHEN f.DataType = 'lookup' and f.FieldNum = 4 THEN dt.Value4
WHEN f.DataType = 'lookup' and f.FieldNum = 5 THEN dt.Value5
WHEN f.DataType = 'lookup' and f.FieldNum = 6 THEN dt.Value6
WHEN f.DataType = 'lookup' and f.FieldNum = 7 THEN dt.Value7
WHEN f.DataType = 'lookup' and f.FieldNum = 8 THEN dt.Value8
WHEN f.DataType = 'lookup' and f.FieldNum = 9 THEN dt.Value9
ELSE NULL
END as INT) as [IntVal]
FROM Lookups as i
left JOIN Fields f on i.FieldId = f.id and i.EntityId = f.EntityId
INNER join DataTable dt on i.EntityId = dt.EntityId
有没有更简单的方法来实现这一点?我需要将其保存在索引视图中,因此不能使用存储过程、函数等。
编辑:
尝试通过以下 cmets 中所述的函数来实现此目的,但发现了同样的问题。以下是我尝试的函数解决方案。
SELECT
dt.Id as [Id],
f.Id as [FieldId],
f.EntityId as [EntityId],
CASE
WHEN f.DataType = 'string' THEN dbo.u_function_return_string
(
f.FieldNum, dt.Value0, dt.Value1,
dt.Value2, dt.Value3, dt.Value4,
dt.Value5, dt.Value6, dt.Value7,
dt.Value8, dt.Value9
)
ELSE NULL
END as [StringVal],
CAST(CASE
WHEN f.DataType = 'lookup' THEN dbo.u_function_returns_string
(
f.FieldNum, dt.Value0, dt.Value1,
dt.Value2, dt.Value3, dt.Value4,
dt.Value5, dt.Value6, dt.Value7,
dt.Value8, dt.Value9
)
ELSE NULL
END as INT) as [IntVal]
FROM dbo.Lookups as i
INNER JOIN dbo.Fields f on i.FieldId = f.id and i.EntityId = f.EntityId
INNER join dbo.DataTable dt on i.EntityId = dt.EntityId
功能:
CREATE FUNCTION u_function_return_string(
@fieldNum INT,
@val0 NVARCHAR(255),
@val1 NVARCHAR(255),
@val2 NVARCHAR(255),
@val3 NVARCHAR(255),
@val4 NVARCHAR(255),
@val5 NVARCHAR(255),
@val6 NVARCHAR(255),
@val7 NVARCHAR(255),
@val8 NVARCHAR(255),
@val9 NVARCHAR(255)
)
RETURNS NVARCHAR(255) WITH SCHEMABINDING
AS BEGIN
RETURN
CASE
WHEN @fieldNum = 0 THEN @val0
WHEN @fieldNum = 1 THEN @val1
WHEN @fieldNum = 2 THEN @val2
WHEN @fieldNum = 3 THEN @val3
WHEN @fieldNum = 4 THEN @val4
WHEN @fieldNum = 5 THEN @val5
WHEN @fieldNum = 6 THEN @val6
WHEN @fieldNum = 7 THEN @val7
WHEN @fieldNum = 8 THEN @val8
WHEN @fieldNum = 9 THEN @val9
END
END
GO
有没有办法将“行”嵌入到函数中?理想情况下,我想提交 2 个参数,字段编号和“dt”结果集。
编辑 2:
找到了一种使函数采用类型的方法...可行...但无法弄清楚如何将查询中的“dt.*”解析为该类型并传递给函数。
CREATE OR ALTER FUNCTION u_function_return_string(
@fieldNum INT,
@data dbo.DataTableType READONLY
)
RETURNS NVARCHAR(255) WITH SCHEMABINDING
AS BEGIN
DECLARE @tmp NVARCHAR(255)
DECLARE @value NVARCHAR(255)
set @tmp = 'Value' + CAST(@fieldNum as NVARCHAR(50))
SET @value = (SELECT @tmp FROM @data)
RETURN @value
END
GO
【问题讨论】:
欢迎来到 EAV 的世界。 对于那些一起玩的人:[实体属性值]sqlblog.com/blogs/aaron_bertrand/archive/2009/11/19/… 看起来类似于最终目标的方法,但对我的问题没有帮助:( “我需要将它保存在视图中,因此不能使用存储过程或任何东西。”。甚至没有功能? 您可以在使用模式绑定功能的模式绑定视图上创建索引。 【参考方案1】:您可以利用标量值模式绑定函数和动态 sql,并在选择查询中用一个 case 函数调用替换多个 case 语句。
我已修改您的查询以解释该方法。请根据您的要求进行更改。
SELECT
dt.Id as [Id],
f.Id as [FieldId],
f.EntityId as [EntityId],
CASE
WHEN f.DataType = 'string' THEN
dbo.fn_getvalue(f.FieldNum,f.EntityId)
ELSE NULL
END as [StringVal],
CAST(CASE
WHEN f.DataType = 'lookup' THEN
dbo.fn_getvalue(f.FieldNum,f.EntityId)
ELSE NULL
END as INT) as [IntVal]
FROM Lookups as i
left JOIN Fields f on i.FieldId = f.id and i.EntityId = f.EntityId
INNER join DataTable dt on i.EntityId = dt.EntityId
CREATE FUNCTION [dbo].[fn_getvalue]
(@param1 int, @param2 int)
RETURNS nvarchar(255) WITH SCHEMABINDING
AS
BEGIN
declare @sql nvarchar(max);
declare @output nvarchar(50);
set @sql = 'SELECT @field=Value' + @param1 + ' FROM DataTable WHERE EntityId = ' + cast(@param2 as nvarchar);
execute sp_executesql @sql,N'@field nvarchar(50) OUTPUT', @field = @output OUTPUT;
return @output;
END
【讨论】:
不幸的是,这种方法的性能在大约 10k 记录后急剧下降 - 对于案例语句,它在执行查询方面相对一致。以上是关于带演员表的选择中的动态“列”的主要内容,如果未能解决你的问题,请参考以下文章