首页 > 解决方案 > 带有特殊字符“İ”的数据库名称

问题描述

很久以前有人创建了具有特殊字符名称的数据库,例如“PRİNCE”。所以我们不能再更改数据库名称了。因为 'İ' 我们不能从 sys.databases 调用数据库。

select name
from dbo.sysdatabases
where name=cast('PRİNCE' as varchar(100)) COLLATE SQL_Latin1_General_CP1253_CI_AI  

它运作良好

但是有一个我们使用的程序会给出错误“数据库'PRİNCE'不存在。确保名称输入正确。

DECLARE @dbname VARCHAR(50) -- database name 
Declare @strSQL nvarchar(max)

DECLARE c CURSOR FOR 
select name from MASTER.dbo.sysdatabases where (name not in('master','model','msdb','tempdb'))


OPEN c;  
FETCH NEXT FROM c INTO @dbname;  

WHILE @@FETCH_STATUS = 0  
begin
select @strSQL='use '+cast(@dbname as varchar(100))COLLATE SQL_Latin1_General_CP1253_CI_AI+' Select  Db_name(DB_ID()) as Dbname from sys.database_files ;'
exec sp_executesql @strSQL
fetch next from c into @dbname
end
close c
deallocate c

标签: sql-server

解决方案


问题是您使用了varchar整个而不是nvarchar. 具体的问题陈述是这样的:

select @strSQL='use '+cast(@dbname as varchar(100))COLLATE SQL_Latin1_General_CP1253_CI_AI+' Select  Db_name(DB_ID()) as Dbname from sys.database_files ;'

我猜你的数据库(master我假设)不在排序规则中,SQL_Latin1_General_CP1253_CI_AI所以一旦分配发生,值就会丢失。

例如,请参见以下内容:

DECLARE @Database sysname = N'USE ' + 'İ' COLLATE  SQL_Latin1_General_CP1253_CI_AI + ';';
SELECT @Database;

这返回USE I; not USE İ;。由于对象名称是sysname(的同义词nvarchar(128) NOT NULL),因此请确保您通过代码使用该数据类型:

USE master;
GO
DECLARE @dbname sysname; -- database name 
DECLARE @strSQL nvarchar(max);

DECLARE c CURSOR FOR 
SELECT [name]
FROM sys.databases --Don't use the old objects!
WHERE ([name] NOT IN(N'master',N'model',N'msdb',N'tempdb'));

OPEN c;  
FETCH NEXT FROM c INTO @dbname;

WHILE @@FETCH_STATUS = 0 BEGIN
    SET @strSQL = N'USE ' + QUOTENAME(@dbname) + N'; SELECT DB_NAME(DB_ID()) AS DBName from sys.database_files;'; --Note QUOTENAME as well for proper quoting.
    EXEC sys.sp_executesql @strSQL;
    FETCH NEXT FROM c INTO @dbname;
END;
CLOSE c;
DEALLOCATE c;

理想情况下,我也会摆脱它CURSOR,但这是一个完全不同的问题。


推荐阅读