我已经做了一些搜索,但还是没有达到我的需要。
我受限于阻止我使用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语句,由于我公司的编码标准,我无法做到这一点。
任何建议都将不胜感激。
答案 0 :(得分:0)
假设您确实有权创建临时表,并且您已经具有将各种CASE语句放在表中的逻辑(以及一些其他假设,这些假设可能有效也可能无效,但仍暗示但在此处缺少明确的描述) ,下面的方法怎么样:
CREATE TABLE #TempTest
(
ID INT,
Data VARCHAR(50),
Data2 VARCHAR(50),
Flag INT
)
CREATE TABLE #TempCase
(
ID INT,
CaseS VARCHAR(50),
CaseSDataType VARCHAR(20),
HasProcessed BIT DEFAULT(0)
)
INSERT INTO #TempCase
(ID,
CaseS,
CaseSDataType)
VALUES (1,
'CASE WHEN Flag = 1 THEN Data ELSE Data2 END',
'VARCHAR(50)'),
(2,
'CASE WHEN Flag = 2 THEN ID ELSE 0 END',
'VARCHAR(50)')
INSERT INTO #TempTest
(ID,
Data,
Data2,
Flag)
VALUES (1,
'Hobo',
'Jim',
1),
(2,
'Hobo Again',
'Jane',
2)
CREATE TABLE #Computed ( ID INT )
INSERT INTO #Computed ( ID ) SELECT ID FROM #TempTest
DECLARE @caseID INT
DECLARE @caseSQL VARCHAR(100)
DECLARE @colSQL VARCHAR(100)
DECLARE @updateSQL VARCHAR(255)
WHILE EXISTS( SELECT * FROM #TempCase WHERE HasProcessed = 0 )
BEGIN
SELECT TOP 1
@caseID = ID,
@caseSQL = REPLACE(REPLACE('ALTER TABLE #TempTest ADD CaseStmt{id} AS ({stmt})', '{id}', CAST(ID AS VARCHAR)), '{stmt}', CaseS),
@colSQL = REPLACE(REPLACE('ALTER TABLE #Computed ADD CaseStmt{id} {datatype}', '{id}', CAST(ID AS VARCHAR)), '{datatype}', CaseSDataType),
@updateSQL = REPLACE('UPDATE t2 SET t2.CaseStmt{id} = t1.CaseStmt{id} FROM #TempTest t1 INNER JOIN #Computed t2 ON t1.ID = t2.ID', '{id}', ID)
FROM #TempCase
WHERE HasProcessed = 0
-- Add the columns
EXEC(@caseSQL)
EXEC(@colSQL)
-- Update the column
EXEC(@updateSQL)
-- Next
UPDATE #TempCase
SET HasProcessed = 1
WHERE ID = @caseID
END
-- Return your results (all of #Computed)
SELECT * FROM #Computed
实际上,#Computed的结构就像各种CASE语句在一个SELECT语句中被链接在一起一样。
我们可以通过简单地将CASE语句直接戳到UPDATE sql来快捷创建计算列,但这可能需要对CASE语句进行一些操作以确保表前缀正确。
答案 1 :(得分:0)
以您向SQL Injection公开的方式构建动态SQL!
无论如何,您可以将第一个EXEC
的结果插入临时表并执行它:
CREATE TABLE #final(result VARCHAR(8000));
INSERT INTO #final(result)
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 #TempTest''
FROM #TempCase TC
GROUP BY TC.ID');
DECLARE @sql VARCHAR(8000);
SELECT @sql = result
FROM #final;
EXEC(@sql);
的 LiveDemo
强>
输出:
╔══════╦══════╗
║ col1 ║ col2 ║
╠══════╬══════╣
║ Hobo ║ 0 ║
║ Jane ║ 2 ║
╚══════╩══════╝