这两个T-SQL语句有什么区别?

4
在工作中的 SSIS 包中,有一些 SQL 任务用于创建暂存表以保存导入数据。所有语句都采用以下形式:
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'dbo.tbNewTable') AND type in (N'U'))
BEGIN
    TRUNCATE TABLE dbo.tbNewTable
END
ELSE
BEGIN
    CREATE TABLE dbo.tbNewTable (
        ColumnA VARCHAR(10) NULL,
        ColumnB VARCHAR(10) NULL,
        ColumnC INT NULL
    ) ON PRIMARY
END

在Itzik Ben-Gan的T-SQL基础中,我看到了一种不同的创建表语句形式:
IF OBJECT_ID('dbo.tbNewTable', 'U') IS NOT NULL
BEGIN
    DROP TABLE dbo.tbNewTable
END

CREATE TABLE dbo.tbNewTable (
    ColumnA VARCHAR(10) NULL,
    ColumnB VARCHAR(10) NULL,
    ColumnC INT NULL
) ON PRIMARY

每个都似乎做同样的事情。执行后,将在dbo模式中创建一个名为tbNewTable的空表。
这两者之间有实际或理论上的区别吗?它们可能会产生什么影响?

1
临时表在SQL Server中具有特定的含义,而这些类型的表不是它们。你应该称它们为暂存表。根据定义,临时表驻留在temp db中,并以#或##开头。 - HLGEM
好观点,HLGEM。我已经编辑过了,使其更加清晰明了。 - Iain Samuel McLean Elder
4个回答

6

第一个假设如果表存在,则具有与创建时相同的列。而第二个则没有这个假设。因此,如果存在具有不同列集的同名表,两者将产生非常不同的结果。


在这里使用“schema”一词时要小心,因为在Microsoft SQL术语中,它意味着完全不同的东西 :) 只是指出这一点。 - Ayyoudy
+1 是指出了一个假设,即已经存在的 tbNewTable 与可能创建的表具有相同的定义。在我们的数据库中,这个假设在某个时候被违反了(表的定义在其他地方被更改),现在这个包已经无法正常工作了。 - Iain Samuel McLean Elder

2
第一个实际上不会删除表,它只是将该表中的所有数据截断。因此才需要保护 CREATE。
因此,具有 DROP 的形式将允许在创建新表时更改模式(如果 tbNewTable 以前存在)。
由于 DROP/CREATE 修改数据库模式,因此在某些情况下可能也不被允许。例如,使用 SCHEMABINDING 创建的视图将防止删除表(如果存在更一般的 FK 关系,则同样适用)。
当指定了 SCHEMABINDING 时,“基表或表不能以影响视图定义的方式进行修改。”
TRUNCATE 在那些常数“不关心”的方式中应该稍微快一点:在其中一个上没有性能考虑。
也有权限差异。 TRUNCATE 只需要 ALTER 权限。

所需的最小权限是对 table_name 的 ALTER 权限。TRUNCATE TABLE 权限默认为表所有者...

祝编码愉快。

1

这些是非常不同的。

第一个在sys.objects系统表上执行相等性检查,并查看是否有匹配的表名。如果是,则截断表格。基本上删除所有行,但保留表结构本身 - 即实际表从未被删除。

在第二个中,使用OBJECT_ID()方法隐式地检查表是否存在。如果是,则完全删除表格 - 行和结构。

如果您在表上有主键和外键约束,您肯定会遇到完全删除它的问题...如果您有其他链接到您正在尝试“截断”的表的表,除非您打开级联删除,否则您也会遇到问题。


1

我倾向于不喜欢在SSIS包中使用任何构造。我会在部署脚本中创建表,如果后来使用的其中一个表不存在,则希望包失败,因为这意味着发生了严重错误,并且我希望在尝试将数据放置在任何位置之前先调查一下。


建议在部署脚本中创建表格,这样表格就成为数据库的一部分,而不是包的一部分。这样我们可以更容易地捕捉到关于表格的假设已经改变,因为对表格的操作将会失败。 - Iain Samuel McLean Elder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接