Как определить столбец (столбцы), отвечающие за «Строка или двоичные данные будут обрезаны».

31

Я генерирую некоторые запросы автоматически с помощью кода, который я написал в SELECT из удаленной базы данных Pg, и вставляю в локальную базу данных SQL Server. Тем не менее, один из них генерирует эту ошибку:

[Microsoft] [Драйвер ODBC SQL Server] [SQL Server] Строка или двоичные данные будут усечены. (SQL-22001) [состояние было 22001, теперь 01000]

[Microsoft] [Драйвер ODBC SQL Server] [SQL Server] Оператор был прерван. (SQL-01000) at. \ Insert.pl, строка 106.

Как узнать, какой столбец генерирует эту ошибку и не хватает длины для ввода? Есть ли способ сделать это без грубой силы, угадывая все varchar?

Эван Кэрролл
источник

Ответы:

35

Нет, это нигде не зарегистрировано. Пойди проголосуй и изложи свое экономическое обоснование; это один из длинного списка вещей, которые должны быть исправлены в SQL Server.

Это было запрошено несколько лет назад в Connect (возможно, сначала в период SQL Server 2000 или 2005), а затем снова в новой системе обратной связи:

И теперь он поставляется в SQL Server 2019 , SQL Server 2017 CU12 и появится в будущем SQL Server 2016 SP2 CU.

В самой первой общедоступной CTP-версии SQL Server 2019 он отображается только под флагом трассировки 460. Это звучит как секрет, но он был опубликован в этом техническом описании Microsoft . В дальнейшем это будет поведение по умолчанию (флаг трассировки не требуется), хотя вы сможете управлять этим через новую конфигурацию области базы данных VERBOSE_TRUNCATION_WARNINGS.

Вот пример:

USE tempdb;
GO
CREATE TABLE dbo.x(a char(1));

INSERT dbo.x(a) VALUES('foo');
GO

Результат во всех поддерживаемых версиях до SQL Server 2019:

Сообщение 8152, уровень 16, состояние 30, строка 5
Строка или двоичные данные будут обрезаны.
Заявление было прекращено.

Теперь на CTP-серверах SQL Server 2019 с включенным флагом трассировки:

DBCC TRACEON(460);
GO

INSERT dbo.x(a) VALUES('foo');
GO
DROP TABLE dbo.x;
DBCC TRACEOFF(460);

Результат показывает таблицу, столбец и значение ( усеченное , не полное ):

Сообщение 2628, уровень 16, состояние 1, строка 11
Строка или двоичные данные будут обрезаны в таблице «tempdb.dbo.x», столбец «a». Усеченное значение: 'f'.
Заявление было прекращено.

Пока вы не можете отбросить все и выполнить обновление до SQL Server 2019 или перейти на базу данных SQL Azure, вы можете изменить свой «автоматический» код, чтобы фактически получать значение max_length sys.columnsвместе с именем, которое вы все равно должны получить, а затем применять LEFT(column, max_length)или какой бы ни был эквивалент PG. Или, поскольку это просто означает, что вы будете молча терять данные, выясните, какие столбцы не совпадают, и исправьте столбцы назначения, чтобы они соответствовали всем данным из источника. Учитывая доступ к метаданным в обеих системах и тот факт, что вы уже пишете запрос, который должен автоматически сопоставлять столбцы источника -> назначения (в противном случае эта ошибка вряд ли будет вашей самой большой проблемой), вам не нужно делать никакой грубой силы гадать на всех.

Аарон Бертран
источник
2

Если у вас есть доступ к мастеру импорта и экспорта SQL Server из среды SQL Server Management Studio (щелкните правой кнопкой мыши базу данных> Задачи> Импорт данных ...), создайте задачу, которая импортирует из клиента SQL, используя ваш запрос в качестве источника данных для назначения. стол.

Перед запуском импорта вы можете просмотреть сопоставление данных, и оно сообщит вам, какие столбцы имеют несовместимые типы полей. И если вы запустите задачу импорта, она скажет вам, какие столбцы не удалось импортировать.

Предупреждение о проверке образца:

Предупреждение 0x802092a7: Поток данных Задача 1. Обрезание может произойти из-за вставки данных из столбца потока данных «NARRATIVE» длиной 316 в столбец базы данных «NARRATIVE» длиной 60. (Мастер импорта и экспорта SQL Server)

bubbassauro
источник
1

В конечном счете, я не смог найти способ получить информацию о колонке, не написав ее сам.

Это сообщение об ошибке было сгенерировано DBD::ODBC, вы также можете использовать sys.columns (max_length)(я просто не знаю, как).

Я использовал такой код в своем списке столбцов, чтобы получить список массивов с двумя элементами COLUMN_NAME, и, MAX_LENGTH(задокументировано в DBIcolumn_info() ).

my @max_lengths = map [ @{$_->fetchall_arrayref->[0]}[3,6] ]
    , map $dbh_mssql->column_info('database', 'dbo', $dest_table, $_)
    , @col_mssql
;

Затем я уловил исключения INSERTи распечатал что-то полезное. В этом примере @$rowданные отправляютсяsth->execute()

if ($@) {
        warn "$@\n";
        for ( my $idx=0; $idx <= $#{ $row }; $idx++ ) {
                Dumper {
                        maxlength => $max_lengths[$idx]->[1]
                        , name    => $max_lengths[$idx]->[0]
                        , length  => length( $row->[$idx] )
                        , content => $row->[$idx]
                };
        }
        die;
}

Также, пожалуйста, проголосуйте и проголосуйте за другой ответ

Эван Кэрролл
источник
2
Я не помещал никаких ссылок на код, sys.columnsпотому что я совершенно не представлял, какой код вы сейчас используете для «автоматического» генерирования ваших запросов. Там действительно не так много сложнее, я мог бы догадаться о включении в ваш код, чем SELECT name, object_id, max_length FROM sys.columns;. Поскольку у вас уже есть автоматический код, который должен это делать - или что-то очень похожее - я не думаю, что пример необходим.
Аарон Бертран
Я не уверен, как sys.columnsработает с двумя столбцами, которые имеют одинаковые name. Кроме того, я получил работу с библиотекой, а не sys, почему я сделал это в качестве выбранного ответа? Microsoft SQL doesn't have x, do y insteadЭто действительный вклад, но если вы yуступаете моему y, я собираюсь сделать что-то другое и пометить его как выбранное.
Эван Кэрролл
1
По сути, ваш вопрос был в том, как мне узнать, в каком столбце возникла ошибка (предположительно, чтобы вы могли исправить это в одном месте, вместо того, чтобы заново разрабатывать решение). Я сказал вам, где искать: sys.columns. Именно там вы должны посмотреть, чтобы сравнить длину столбцов источника с длинами столбцов назначения. Как вы это делаете, зависит от вас. Я не говорил вам, как исправить ваш код, потому что я абсолютно не представлял, как ваш автоматический запрос генерировался в первую очередь, поэтому, как я уже сказал, понятия не имел, как добавить определения длины в любой запрос, который у вас уже был. ,
Аарон Бертран
1

Наконец, Microsoft решила предоставить значимую информацию для String or binary would be truncatedзапуска с SQL Server 2016 SP2 CU, SQL Server 2017 CU12 и SQL Server 2019.

Теперь информация включает в себя как столбец таблицы с ошибками (полное имя), так и значение с ошибками (усечено до 120 символов):

Сообщение 2628, уровень 16, состояние 1, строка x строка или двоичные данные будут обрезаны в таблице «TheDb.TheSchema.TheTable», столбец «TheColumn». Усеченное значение: '...'. Заявление было прекращено.

Алексей
источник