【发布时间】:2016-03-02 03:17:12
【问题描述】:
我已经进行了一些搜索,但发现有点无法满足我的需求。
我受到编码标准的限制,无法使用 NVARCHAR(MAX) 或 VARCHAR(MAX),这是我的痛点。
我需要创建一个很可能超过 8000 个字符的动态 SQL 语句。发生这种情况的原因是因为要求使用一个巨大的 CASE WHEN 语句。我的方法是将每个 CASE WHEN 作为记录插入到表中。然后我在动态 SQL 语句中使用 XML PATH('') 来创建另一个动态 SQL 语句。
这是我正在使用的代码示例:
CREATE TABLE #TempTest (
ID INT
,Data VARCHAR(50)
,Data2 VARCHAR(50)
,Flag INT
)
CREATE TABLE #TempCase (
ID INT
,CaseS VARCHAR(50)
)
INSERT INTO #TempCase (
ID
,CaseS
)
VALUES
(1,'CASE WHEN Flag = 1 THEN Data ELSE Data2 END')
,(2,'CASE WHEN Flag = 2 THEN ID ELSE 0 END')
INSERT INTO #TempTest (
ID
,Data
,Data2
,Flag
)
VALUES
(1,'Hobo','Jim',1)
,(2,'Hobo Again','Jane',2)
EXEC('SELECT TOP 1 ''SELECT '' + STUFF((SELECT N'', '' + CaseS
FROM #TempCase TC
ORDER BY TC.ID
FOR XML PATH(N''''), TYPE).value(N''.[1]'', N''nvarchar(max)''), 1, 2, N'''') + '' FROM #TempCase''
FROM #TempCase TC
GROUP BY TC.ID')
这个EXEC语句的结果是——
SELECT CASE WHEN Flag = 1 THEN Data ELSE Data2 END, CASE WHEN Flag = 2 THEN ID ELSE 0 END FROM #TempCase
查询的结果是我必须运行的动态 SQL。我试图将我当前的 EXEC 语句嵌套到另一个 EXEC 语句中,但这只会创建两个具有相同结果的数据集。大多数人处理此问题的方式是通过将初始 EXEC 结果设置为 VARCHAR(MAX) 并将其分配给第二个 EXEC 语句进行一些搜索,由于我公司的编码标准,我无法这样做。
任何建议将不胜感激。
【问题讨论】:
-
为什么不使用
EXEC sp_executesql @sql,那么@sql可以是NVARCHAR(MAX)? -
限制是有原因的 - 使用动态 SQL 很糟糕,因为它会使您暴露于 sql 注入,并且如果您获得单个字符,则 非常 难以维护和调试错误的。超过 8000 个字符的动态 SQL 语句非常不好,因为维护它几乎是不可能的。性能也可能非常糟糕,因为优化器将很难为如此复杂的查询制定计划。为什么不用 CASE 语句创建一个或多个视图并且只选择您想要的字段?或者将大查询分解为多个查询,然后与 UNION ALL 结合使用?
-
因为我不能使用 NVARCHAR(MAX) - @sql 仍然必须定义为 NVARCHAR(MAX)。
-
我了解 SQL 注入的问题,但是该过程没有用户前端,因此不是真正的问题。我已经只选择了我需要的字段,但是根据记录中返回的内容确定输出,因此需要 CASE WHEN 语句。信息来自不同的服务器,因此我只想查询一次数据。
-
但是在通过 FOR XML 连接之后,在转换从 xml 输出中提取的值时,您使用 nvarchar(max) 作为 sql 类型,因此即使您可以执行 exec(exec) 它仍然是违反编码标准
标签: tsql sql-server-2012