【问题标题】:SQL Server 2014 'Incorrect syntax near the keyword 'select'.'SQL Server 2014 '关键字'select'附近的语法不正确。'
【发布时间】:2014-06-02 17:44:21
【问题描述】:

下面的sql代码有什么问题吗:

ALTER TABLE [idconfirm].[EPS_ENROLLMENT] 
DROP CONSTRAINT select d.name from syscolumns c,sysobjects d, sysobjects t 
where c.id=t.id AND d.parent_obj=t.id AND d.type='D' AND t.type='U' 
AND c.name='ENC_TOKEN_KEK_SALT_SIZE' AND t.name='EPS_ENROLLMENT';

【问题讨论】:

  • 您可以尝试将SELECT 语句括在括号(..) 中
  • 如果您不知道要删除的约束的名称,则需要使用动态 SQL - 您还应该了解 JOIN,它只是标准 SQL 的一部分~ 20 年。
  • 为什么每个人都还在谈论糟糕的旧式连接? sqlblog.com/blogs/aaron_bertrand/archive/2009/10/08/…

标签: sql sql-server sql-server-2014


【解决方案1】:

你不能只说

 ALTER TABLE FOO DROP CONSTRAINT;

你必须给一个约束名称:

 ALTER TABLE FOO DROP CONSTRAINT CONS_SOME_CONS_NAME;

您似乎正在尝试使用后一个查询来返回约束名称的结果集?你不能用这样的 SELECT 来提供 ALTER 语句,它也不起作用。要么使用 SQL 生成脚本,然后保存脚本并运行它,要么使用动态 SQL。

动态 SQL 是 丢弃 对象时使用的最危险 做法之一,但我看到它在 StackOverflow 上如此随意地提出。除非您需要自动化并且需要能够适应潜在差异的脚本(例如向客户部署更改脚本),否则您不会使用它。否则,您应该练习安全 DBA 并将脚本生成到文本窗口,然后在执行之前对其进行验证。动态 SQL 直接从生成跳转到执行。多花 15 秒时间验证。

您可以保存它并将其部署到其他数据库,并且知道只有该脚本中的操作会运行。部署动态 SQL 还可能为每个数据库部署不同的操作;有时这是你想要的,有时不是。

要像这样生成 DDL,请从 SSMS 菜单中选择“Results to Text”,或简称为 CTRL-T,然后运行:

SELECT 'ALTER TABLE T DROP CONSTRAINT ' + d.name
  from syscolumns c, sysobjects d, sysobjects t 
    where c.id=t.id AND d.parent_obj=t.id AND d.type='D' AND t.type='U' 
      AND c.name='ENC_TOKEN_KEK_SALT_SIZE' AND t.name='EPS_ENROLLMENT';

然后你就有了你的脚本,复制粘贴它,验证它,保存它。这种技术适用于任何具有数据字典目录的数据库。

【讨论】:

  • 虽然是真的,但这没有达到目标的意图。
  • 这就是为什么我们有一个投票系统,您可以提供比我更好的答案并获得投票。 :)
【解决方案2】:

ALTER TABLE .. DROP CONSTRAINT SELECT .. 是not valid syntax;在 DROP CONSTRAINT 之后需要一个 标识符(“constraint_name”)。

与所有SQL DDL 一样,列标识符不是值,并且不能是表达式(SELECT 或其他)的结果。要在这样的语句中使用值需要构建和executingDynamic SQL。

例如,

declare @name varchar(200)

-- I recommend not using implicit cross-joins, but ..
select @name=d.name
from syscolumns c, sysobjects d, sysobjects t 
where c.id=t.id AND d.parent_obj=t.id AND d.type='D' AND t.type='U' 
  AND c.name='ENC_TOKEN_KEK_SALT_SIZE' AND t.name='EPS_ENROLLMENT';

-- Build dynamic SQL
SET @sql = 'ALTER TABLE idconfirm.EPS_ENROLLMENT DROP CONSTRAINT ' + @name;
-- And execute it
EXEC (@sql)

【讨论】:

    【解决方案3】:

    你真的不应该使用sysobjects,因为它已经被弃用了很长时间。事实上,我很难理解为什么还没有其他人指出这一点。虽然其他人对您的 SQL 语句问题的分析是正确的(尤其是 @mrjoltcola,他很好地解释了您的语句错误的原因),但作为回答这个问题的假定专家,我们也应该教育那些提出问题的人以确保他们不使用过时和不推荐使用的语法。此外,如果有机会提高 OPs 代码的质量,我们也应该抓住它,以减少他们在某个时候回来抱怨他们的代码因为升级服务器或其他原因而损坏的可能性(当然,我知道这是关于 SQL 2014 但下一次更新可能会切断sysobjects 的膝盖,因为达摩克利斯之剑已经挂在它上面足够长的时间了)。

    因此,考虑到所有这些,我将使用sys.columns、sys.tables 和sys.default_constraints 以及使用显式INNER JOINS 来调整mrjoltcola 的答案。

    SELECT 'ALTER TABLE [idconfirm].[EPS_ENROLLMENT] DROP CONSTRAINT ' + d.[name]
    FROM sys.tables t 
    INNER JOIN sys.columns c
        ON c.[object_id] = t.[object_id]
    INNER JOIN sys.default_constraints d
        ON d.[parent_object_id] = t.[object_id]
        AND d.[parent_column_id] = c.[column_id]
    
    WHERE t.name='EPS_ENROLLMENT'
        AND  c.name='ENC_TOKEN_KEK_SALT_SIZE';
    

    这将为您提供该表和列的删除代码。当然,如果您需要像这样以编程方式执行整个操作,您可以将该查询的结果分配给 NVARCHAR 变量,然后调用 sp_executesql。

    EXEC sp_executesql @sql
    

    但是,使用动态 SQL 很容易遇到麻烦,所以如果您完全不确定,那么我会尽可能避免使用它 - 它确实应该是最后的手段。

    【讨论】:

      【解决方案4】:

      您不需要提供约束名称来放入您之前的 alter 语句吗?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-08-02
        • 2017-01-08
        • 2013-12-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-18
        相关资源
        最近更新 更多