ALTER TABLE…从常规表切换到分区表失败


9

下面的代码执行以下操作:

  1. 在C:\ TEMP中创建一个数据库play_partition
  2. 创建两个相同的分区表play_table和archive_play_table
  3. 将play_table分区1切换到archive_play_table分区1
  4. 在与play_table分区2相同的文件组上,创建一个新的未分区表temp_table,其结构与play_table相同。
  5. 将play_table_partition 2切换到temp_table
  6. 尝试将temp_table切换回play_table分区2并失败

    消息4982,级别16,状态1,第64行ALTER TABLE SWITCH语句失败。检查源表'play_partition.dbo.temp_table'的约束是否允许目标表'play_partition.dbo.play_table'上分区2定义的范围所不允许的值。

为什么会失败?

我正在使用SQL Server 2014(企业版试用版)。

问候,

科林·戴利

http://www.colindaley.com/translator

/* Playing with partitioned tables */

USE master;
GO

DROP DATABASE play_partition;
GO

CREATE DATABASE play_partition
    ON PRIMARY(
        NAME = play_partition
        , FILENAME = 'C:\TEMP\play_partition.mdf')
    ,FILEGROUP play_fg1(
        NAME = play_fg1
        ,FILENAME = 'C:\TEMP\play_fg1f1.ndf')
    ,FILEGROUP play_fg2(
        NAME = play_fg2f1
        ,FILENAME = 'C:\TEMP\play_fg2f1.ndf');
GO

USE play_partition;


CREATE PARTITION FUNCTION play_range(INT)
    AS RANGE LEFT FOR VALUES(3);

-- Partition scheme
CREATE PARTITION SCHEME play_scheme 
    AS PARTITION play_range TO (play_fg1, play_fg2);

-- Partitioned tables
CREATE TABLE dbo.play_table(
    c1 INT NOT NULL CONSTRAINT PK_play_table_c1 PRIMARY KEY CLUSTERED
)
    ON play_scheme(c1);

CREATE TABLE dbo.archive_play_table(
c1 INT NOT NULL CONSTRAINT PK_archive_play_table_c1 PRIMARY KEY CLUSTERED
)
    ON play_scheme(c1);

-- partition 1 = {1, 2, 3}, partiion 2 = {4, 5, 6}
INSERT INTO dbo.play_table(c1) VALUES (1), (2),  (3), (4), (5), (6);

-- move partition 1 from play_table to archive play_table
ALTER TABLE dbo.play_table
    SWITCH PARTITION 1 to dbo.archive_play_table PARTITION 1;

-- create empty table with same structure as dbo.play_table
SELECT * INTO dbo.temp_table FROM dbo.play_table WHERE 1 = 0;

-- move temp_table to filegroup play_fg2
ALTER TABLE dbo.temp_table
    ADD CONSTRAINT PK_temp_table_c1 PRIMARY KEY CLUSTERED(c1) ON play_fg2;

-- move contents of play_table to temp_table, which is not partitioned
-- but is in the same filegroup
ALTER TABLE dbo.play_table
    SWITCH PARTITION 2 TO temp_table;
PRINT 'Switched from partitioned table to non-partitioned table';

-- move data back to partitioned play_table from unpartitioned temp_table
-- FAIL
ALTER TABLE dbo.temp_table
    SWITCH TO play_table partition 2;
PRINT 'Switched from non-partitioned table to partitioned table';


SELECT 'archive_play_table' as table_name, t1.c1
    FROM dbo.archive_play_table AS t1
    UNION ALL
    SELECT 'temp_table' AS table_name, t1.c1
        FROM dbo.temp_table as t1
    ORDER BY 1, 2;

为您的问题+1。由于您在此处放置了DDL,因此您可以轻松地进行复制和回答。为此,谢谢。我希望我可以提出10多个这样的问题。
Thomas Stringer 2014年

谢谢。该错误需要更好的信息。当它提到表上的检查约束时(没有检查约束时),我没有想到缺少检查约束实际上是问题所在。
Colin Daley 2014年

Answers:


11

当您使用分区切换时,SQL Server将需要验证源表/分区边界是否适合目标表/分区边界。换句话说,您正在尝试将数据从切换dbo.temp_tabledbo.play_table分区2。像这样考虑,c1in dbo.temp_table的数据仅受数据类型(int)约束,因此您的值范围为-2,147,483,648到2,147,483,647 。但是相反,您的目的地(dbo.play_table分区2)的范围是4到2,147,483,647。

您的数据没有违反此规定,但是元数据不允许这样做。您可以轻松地将值-10插入dbo.temp_table。分区切换将以相同的方式失败并且变得更有意义,因为-10不适合dbo.play_table的第二个分区边界。

如果您想使此代码正常工作,则需要明确告知SQL Server,dbo.temp_table它将永远不会有不适合dbo.play_table第二分区的数据。您可以使用检查约束来做到这一点:

/******************************************************************************
    your code omitted for brevity
******************************************************************************/

-- move contents of play_table to temp_table, which is not partitioned
-- but is in the same filegroup
ALTER TABLE dbo.play_table
    SWITCH PARTITION 2 TO temp_table;
PRINT 'Switched from partitioned table to non-partitioned table';

/******************************************************************************
    added check constraint so that data can fit in the destination partition
******************************************************************************/
alter table dbo.temp_table
add constraint CK_TempTable_C1 check (c1 >= 4);
go
/******************************************************************************
    end of added code
******************************************************************************/

-- move data back to partitioned play_table from unpartitioned temp_table
-- this will no longer FAIL
ALTER TABLE dbo.temp_table
    SWITCH TO play_table partition 2;
PRINT 'Switched from non-partitioned table to partitioned table';

/******************************************************************************
    your code omitted for brevity
******************************************************************************/

以上示例代码已添加到代码中,这使它成为可行的解决方案。现在,SQL Server知道由于向中添加了检查约束dbo.temp_tabledbo.play_table因此其中的数据可以放入分区2中dbo.temp_table

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.