(请注意,这是在 SQL Server 2008 上,但我有一位同事在 SQL Server 2014 上报告了同样的问题。)
我正在使用一个支持多个数据库后端的框架,我们的应用程序有一个名为 sysUsers
的表,它在 MySQL 中运行良好。
我们现在需要在 SQLServer 上安装它,这个名称似乎与内置系统 View 冲突。系统 View 是sys.sysusers
,应用表是dbo.sysUsers
。
我知道大小写差异与 SQL Server 无关,但是由于某种原因似乎忽略了架构。
SELECT * FROM sys.sysusers;
从sys.sysusers
返回记录。这完全符合预期。SELECT * FROM sysUsers;
从sys.sysusers
返回记录。这令人惊讶(我原以为本地模式会优先)但也许可以解释。- 但是,
SELECT * FROM dbo.sysUsers;
仍然返回来自sys.sysusers
的记录。这似乎完全错误,因为我明确选择了dbo
架构。
我没有在 MS 文档中找到任何说明这些名称已保留的内容。
我已经尝试重命名表并修改代码以使用不同的名称,一切正常(即这与应用程序中的 SQLServer 集成无关)并且从管理运行查询时看到相同的结果直接控制台。因此,这看起来肯定是表名冲突的问题,而不是中间件错误或语法差异。
如果这个表名是保留的,为什么 MSSMS 允许我创建它?如果不是reserved,为什么不让我查询呢?
以及我如何在不需要应用程序更新的情况下解决这个问题(因为这对于其他部署来说是一个令人头疼的迁移问题)。
最佳答案
至少有三种解决方法,但都不能保证无需重写任何代码(除了非常不安全的那个):
- 在创建数据库时使用区分大小写的排序规则(
CREATE DATABASE Foo COLLATE Latin1_General_CS_AS
)。在这种情况下,sysUsers
在所有情况下都将是与sysusers
不同的对象。您可以在创建数据库后立即设置不区分大小写的排序规则,这样您的数据就不会区分大小写,因为这可能不是最终用户想要的。显然,如果您的应用程序实际上依赖于不区分大小写的对象名称,那么这将不起作用,除非您仔细地重写您的查询。请注意,这意味着所有数据库对象(即使是之后创建的对象)都将具有区分大小写的名称,因为它在创建时嵌入到系统表中并且之后无法更改。 - 使用
dbo
以外的架构。系统表映射仅针对该方案发生,不会针对任何其他方案发生。如果您的应用程序独占使用自己的架构,则您在其中创建的任何sysusers
都不会别名为sys.sysusers
。 (这在任何地方都没有记录,但它是如何工作的。)请注意,为了使其工作,您必须始终明确指定模式,即使它是您用户的默认模式,否则您将再次获得系统表(我认为这是一个错误,但它可能是必要的,因为旧脚本会假定sysusers
在任何地方解析)。 - 启用Dedicated Administrator Connection ,以单用户模式重启SQL Server,将
mssqlsystemresource
数据库切换为READ_WRITE
和DROP VIEW sysusers
。这将从所有 数据库中删除sys.sysusers
。 这样做会使你的保修失效,如果你向他们哭诉,它会导致 Microsoft 支持人员 mock 你,这可能会导致无法安装 future 的 Service Pack 和更新,强烈建议不要这样做,但我无论如何要提一下,为了科学。任何地方的代码都不应该使用这个 View ,但是,你知道,我不是从事 SQL Server 本身工作的工程师。
请注意,降低兼容性级别不是解决方法,我提到它是为了完整性。这对如何解析这些表名没有影响,即使这是一种理想的方法(事实并非如此)。
我认为 SQL Server 2012 中所做的更改忽略了 dbo
限定符并解析为这些旧的、已弃用的名称无论如何都是一个错误,如果由我来决定,我至少会让它成为可能使用跟踪标志选择退出此行为,但这不取决于我。您可以考虑在 Microsoft Connect 上为它提出一个问题,因为当前的行为使得与 RDBMS 无关的代码的运行不必要地变得复杂。
关于sql-server - 名称与 SQL Server 中的 sys.sysusers 系统 View 冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42632840/