像许多其他人一样,我没有多少经验。我被指示将非聚集索引转换为聚簇(不存在聚簇索引)。在附加的查询中,我打印出@sql变量以查看我的命令是什么样的,它只有大约一半的表。
第一个问题。字符串可以执行或打印的时间有限制吗?我试着评论SET @sql = @sql +' UNION ALL'希望我一次可以打印或执行一个命令但不打印任何内容。我真的不想执行,直到我确信我有正确的语法。
SET NOCOUNT ON
IF OBJECT_ID('tempdb..##ListIndex') IS NOT NULL DROP TABLE ##ListIndex
Create Table ##ListIndex (MySchema nvarchar(max), MyTable nvarchar(max), MyIndexName nvarchar(max), MyColumn nvarchar(max), IndexType int)
Insert into ##ListIndex
select s.name, t.name, i.name, c.name, i.type
from sys.tables t
inner join sys.schemas s on t.schema_id = s.schema_id
inner join sys.indexes i on i.object_id = t.object_id
inner join sys.index_columns ic on ic.object_id = t.object_id
inner join sys.columns c on c.object_id = t.object_id and
ic.column_id = c.column_id
where i.index_id =2
and i.type in (1, 2) -- clustered & nonclustered only
and i.is_disabled = 0
and i.is_hypothetical = 0
and ic.key_ordinal > 0
order by s.name asc, t.name desc --ic.key_ordinal
IF OBJECT_ID('tempdb..##ListIndex2') IS NOT NULL DROP TABLE ##ListIndex2
Create Table ##ListIndex2 (MySchema nvarchar(max), MyTable nvarchar(max), MyIndexName nvarchar(max), MyColumn nvarchar(max))
Insert into ##ListIndex2
SELECT DISTINCT
MySchema
, MyTable
, MyIndexName
, STUFF(
(
SELECT ', ' + MyColumn + ' ASC'
FROM ##ListIndex TInner -- replace with your table
WHERE TOuter.MyTable = TInner.MyTable
AND TOuter.MyIndexName = TInner.MyIndexName
AND TOuter.MySchema = TInner.MySchema
FOR XML PATH('')
), 1, 2, ''
) MyColumn
FROM ##ListIndex TOuter
--select * from ##ListIndex2
SET NOCOUNT ON
DECLARE MyCursor CURSOR FOR
SELECT
MySchema
, MyTable
, MyIndexName
,MyColumn
FROM ##ListIndex2 c
OPEN MyCursor
DECLARE @MySchema VARCHAR(100), @MyTable VARCHAR(100), @MyIndexName VARCHAR(100), @MyColumn VARCHAR(300)
DECLARE @sql VARCHAR(MAX)='';
FETCH FROM MyCursor INTO @MySchema, @MyTable, @MyIndexName, @MyColumn
WHILE @@FETCH_STATUS=0
BEGIN
IF LEN(@sql) > 0
SET @sql = @sql + ' UNION ALL '
SET @sql= @sql + 'CREATE UNIQUE CLUSTERED INDEX ' + @MyIndexName + ' on ' + @MySchema + '.' + @MyTable +' (' + @MyColumn +') WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = ON,ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, DATA_COMPRESSION = PAGE) ON [DefFG] GO '
FETCH FROM MyCursor INTO @MySchema, @MyTable, @MyIndexName, @MyColumn
END
CLOSE MyCursor
DEALLOCATE MyCursor
--exec sp_executesql @sql
print @sql
答案 0 :(得分:1)
对于带有字符串变量的select语句,SQL Server Management Studio确实有大约44,000个字符的限制(至少对于SQL Server 2008,我上次遇到此问题)。但是,完整的SQL仍然会被执行(根据我的经验)。
但是你的问题看起来有所不同。我不确定你要做什么,但是
create unique clustered index . . .
union all
create unique clustered index . . .
不是有效的声明。也许你应该用分号结束并忘记union all
。您使用union all
进行select
次查询。
答案 1 :(得分:0)
聚簇索引通常是表的主键,因为表通过此索引进行物理排序...这使得它成为查找查询的候选者。每次修改索引行时,索引都是"重建"并且表重新组织,因此修改聚簇索引并不是一个好主意,通常使用整数(任何类型,无论是smallint,bigint等)来标识唯一行。复合聚簇索引也是如此。
它们的大小约束是最多16个包含列的900字节。所以,我的建议是创建一个聚簇主键而不是将nvarchar
列转换为聚簇索引
答案 2 :(得分:0)
这里有几点需要改进。一些建议会使其他人过时(主要是关于使用CTE的#14会使其余大部分内容无效),但你说你是SQL Server的新手,所以我会提及它们,因为它们可能有助于未来的项目。为了清楚起见,我强调了两个关键/功能性建议。关于字符串限制(与打印和执行相关)的所述问题的答案低于建议的改进列表。
##
),而应使用本地临时表(#
)##ListIndex
中4个名称字段的数据类型应为SYSNAME
,等同于NVARCHAR(128)
##ListIndex2
全局临时表(全部设置为NVARCHAR(MAX)
)与本地变量(即DECLARE @MySchema VARCHAR(100), @MyTable VARCHAR(100)...
)之间的数据类型不匹配##ListIndex2
(MySchema
,MyTable
和MyIndexName
)中的前3个字段以及所有3个匹配变量的数据类型应为SYSNAME
,等同于到NVARCHAR(128)
IndexType
中来自##ListIndex
的{{1}}字段的数据类型应为sys.indexes.type
而非TINYINT
(根据{{1}的文档3}})INT
的条件不合理,因为:
i.[index_id] = 2 AND i.[type] IN (1, 2)
总是为1,因此无论如何都会被index_id
条件过滤掉i.[index_id] = 2
的作用。那是你要的吗?在任何一种情况下,您只需要其中一个条件:
i.[index_id] = 2
并将i.[index_id] = 2 AND
更改为i.[type] IN (1, 2)
< / LI>
i.[type] = 2
AND i.[type] IN (1, 2)
查询的ORDER BY
;它与如何从Insert into ##ListIndex select...
表中检索行无关,因此浪费资源##ListIndex
的{{1}}函数中的子查询有两个问题:
强> STUFF
中为FOR XML PATH
添加TINYINT
字段,并从KeyOrdinal
填充该字段。然后,您可以在该子查询中的此新字段上添加##ListIndex
子句。ic.key_ordinal
,当一个或多个列也可以ORDER BY
时,对吧?除非您确定所有索引字段都定义为ASC
,否则您还需要为DESC
添加ASC
字段BIT
并填充##ListIndex
}}。您可以在IsDescending
中使用ic.is_descending_key
(CASE
启动IIF
代替硬编码SELECT
的子查询中使用此值。 < / LI>
' ASC'
(就在SET NOCOUNT ON
上方),因为您已经在脚本的开头已经拥有它了DECLARE MyCursor CURSOR
变量应该定义为@sql
而不是NVARCHAR(MAX)
VARCHAR(MAX)
应该是FETCH FROM
FETCH NEXT FROM
行和以下IF LEN
行,因为它们不正确且无用 SET...'UNION ALL'
的行末尾的字符串中,将CREATE UNIQUE...
放在下一行关于字符串执行时间的任何可能限制:GO
或VARCHAR(MAX)
中的任何内容(根据sys.indexes的文档)。我已经在NVARCHAR(MAX)
变量( well 超过4000个字符)中构建了相当多的查询集,并在其上调用EXEC而没有任何问题。
在打印NVARCHAR(MAX)
时,您只看到大约一半表的原因是@sql
命令最多只能打印8000个PRINT
或4000个{{1}个字符的字符VARCHAR
1}},即使您的变量是NVARCHAR
类型。为了打印它,您需要使用MAX
遍历每个4000或8000个字符(取决于NVARCHAR与VARCHAR变量)。
在评论SUBSTRING()
行时您没有看到任何内容的原因是我总是建议在所有SET @sql = @sql + ' UNION ALL '
/ IF
/ etc构造周围放置BEGIN / END标记,即使对于只需一行即可执行。这意味着,通过评论WHILE
行,并且很可能不将SET
与IF
一起评论,然后将IF
语句应用于剩余的SET
1}}并且只运行SET @sql= @sql + 'CREATE UNIQUE...
行 IF LEN(@sql)&gt; 0,它永远不会; - )。
答案 3 :(得分:0)
关于将UNION ALL
与动态SQL一起使用的说明。
如果您需要加入多个查询或批处理,您只需连接像
这样的字符串SET @sql = 'SELECT 1 ' + ' SELECT 2 '
当您使用UNION ALL
创建语句并且您不知道将有多少SELECT(或者您不想打扰它)时 - 创建一个以UNION ALL
结尾的字符串,然后减去最后9-10个字符。
SET @sql = 'SELECT 1 AS col FROM MyTable' + ' UNION ALL ' + ... + ' SELECT 1 FROM MyTable UNOIN ALL'
SET @sql = LEFT (@sql, len(@sql) - 10