2

如何使用 sp_MSforeachtable 为每个表添加索引?它不断给出错误。

EXEC sp_MSforeachtable @precommand = 'declare @idx as char;',
@command1 = '
set @idx = ''idx_'' + ? + ''_modified_on'';
print @idx;
IF  EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N''[dbo].[?]'') AND name = N''@idx'')
    DROP INDEX [@idx] ON [dbo].[?]

CREATE NONCLUSTERED INDEX [@idx] ON [dbo].[?] 
(
    [modified_on] ASC
) ON [PRIMARY]
'

一个这样的错误:

Msg 137, Level 15, State 1, Line 2
Must declare the scalar variable "@idx".

我尝试将声明放在命令中,但随后出现此错误:

Msg 4104, Level 16, State 1, Line 3
The multi-part identifier "dbo.DIAG_contractAuditHistory" could not be bound.

这是修复语法错误的更新尝试,也包含测试 SQL,但它仍然给出了奇怪的错误。我最终用存储过程解决了这个问题,并为每个表调用了存储过程。

EXEC sp_MSforeachtable @command1 = '
declare @idx as varchar(256);
set @idx = ''idx_'' + SUBSTRING(''?'', 8, len(''?'')-8) + ''_modified_on'';
print @idx;
IF  EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N''?'') AND name = @idx   )
    DROP INDEX [@idx] ON ?

IF EXISTS (select * from sys.columns where object_id = OBJECT_ID(N''?'') and name = ''modified_on'')
    CREATE NONCLUSTERED INDEX [@idx] ON ?
    (
        [modified_on] ASC
    ) ON [PRIMARY]
'

declare @cat as char;
set @cat='dog';
print @cat;

EXEC sp_MSforeachtable 'print ''idx_'' + SUBSTRING(''?'', 8, len(''?'')-8) + ''_modified_on'';'
EXEC sp_MSforeachtable 'print ''?'''
print substring('[dbo].[merchantNotes]', 8, (len('[dbo].[merchantNotes]')-9))

select * from sys.columns where object_id = OBJECT_ID(N'[dbo].[banks]') and name = 'modified_on'
SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'contractPaymentHistory') AND name = 'idx_contractPaymentHistory_modified_on'

这适用于大约两打表,然后会出现奇怪的错误,例如

消息 1934,级别 16,状态 1,第 9 行 CREATE INDEX 失败,因为以下 SET 选项的设置不正确:'QUOTED_IDENTIFIER'。验证 SET 选项对于索引视图和/或计算列上的索引和/或过滤索引和/或查询通知和/或 XML 数据类型方法和/或空间索引操作是否正确。

所以我最终使用了不同的策略并创建了一个存储过程来创建索引:如何在存储过程中创建索引?

4

2 回答 2

2

我以前从未尝试过使用@precommand,但是如果您将该部分添加到@command1它应该可以工作。

第二个问题与您的使用方式有关?,它实际上已经包含 dbo 模式。将部分替换OBJECT_ID(N''[dbo].[?]'')OBJECT_ID("?")andCREATE语句DROP INDEX也是如此。

编辑:

这段代码应该可以工作。

EXEC sp_MSforeachtable
    '
        declare @idx as char;
        set @idx = ''idx_'' + "?" + ''_modified_on'';
        IF  EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID("?") AND name = N''@idx'')
            DROP INDEX [@idx] ON ?

        CREATE NONCLUSTERED INDEX [@idx] ON ?
        (
            [modified_on] ASC
        ) ON [PRIMARY]
    '
于 2013-06-21T19:19:17.987 回答
1

您可以在命令中声明 idx。您还有其他语法错误。表决。您的错误与声明语句无关。那是因为你用?错了。sp_msforeachtable将做一个简单的替换。因此,对于您的使用,您需要引用它(或者更确切地说,不要取消引用外部字符串。

请参阅我对您的其他问题的回答,了解为什么这仍然不起作用。

这是一个徒手更正的版本:

EXEC sp_MSforeachtable
@command1 = '
declare @idx nvarchar(1000);
declare @tbl nvarchar(1000);
set @tbl = replace(''?'', ''[dbo].'', '''');
set @tbl = left(@tbl, len(@tbl) - 1);
set @idx = ''idx_'' + @tbl + ''_modified_on'';
print @idx;
IF  EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N''?'') AND name = N''@idx'')
    DROP INDEX [@idx] ON ?;
declare @sql nvarchar(1000);
set @sql = ''
CREATE NONCLUSTERED INDEX ['' + @idx + ''] ON ? 
(
    [modified_on] ASC
) ON [PRIMARY]'';
exec sp_executesql @sql;
';

我应该质疑你为什么要这样做。单独索引该字段并不像您想象的那么好。阅读覆盖索引

于 2013-06-21T19:45:08.917 回答