ALTER TABLE… Переключение с обычной таблицы на разделенную таблицу завершается неудачно

9

Код ниже делает следующее:

  1. Создает базу данных play_partition в C: \ TEMP
  2. Создает две идентичные многораздельные таблицы play_table и archive_play_table
  3. Переключение раздела play_table 1 на раздел archive_play_table 1
  4. Создает новую неразделенную таблицу temp_table с той же структурой, что и play_table в той же файловой группе, что и раздел play_table 2
  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', разрешающие значения, которые не разрешены диапазоном, определенным разделом 2, для целевой таблицы 'play_partition.dbo.play_table'.

Почему это не удается?

Я использую SQL Server 2014 (пробная версия Enterprise Edition).

С Уважением,

Колин Дейли

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 вопросов, как это.
Томас Стрингер
Спасибо. Эта ошибка нуждается в лучшем сообщении. Когда в нем упоминались проверочные ограничения для таблицы (когда проверочных ограничений не было), мне не приходило в голову, что проблема заключается в отсутствии проверочных ограничений.
Колин Дейли

Ответы:

11

Когда вы работаете с переключением разделов, SQL Server должен будет убедиться, что исходная таблица / границы раздела могут соответствовать границам целевой таблицы / раздела. Другими словами, вы пытаетесь данных коммутатора от dbo.temp_tableк dbo.play_table«s раздела 2. Думайте об этом , как это, данные для c1ин dbo.temp_tableограничивается только типом данных ( int), так что вы можете иметь значения в диапазоне от -2147483648 до 2147483647 , Но, наоборот, ваш пункт назначения ( 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_tableмогут помещаться во втором разделе dbo.play_tableиз-за добавленного ограничения проверки для dbo.temp_table.

Томас Стрингер
источник