Как выяснить, какой столбец вызывает ошибку арифметического переполнения при вставке? - PullRequest
7 голосов
/ 08 сентября 2010

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

Мои первоначальные мысли по поводу решения заключаются в том, чтобы обернуть его в транзакцию, которую я, в конечном счете, откатлю и использую своего рода подход «разделяй и властвуй»:

begin tran

insert into BaseTable (c1,c2,c3,...,cN)
select c1,c2,c3,...,cN 
from UserTable

rollback tran

И это, очевидно, не удается. Таким образом, мы разделяем набор столбцов пополам так:

begin tran

insert into BaseTable (c1,c2,c3,...,cK) --where K = N/2
select c1,c2,c3,...,cK --where K = N/2
from UserTable

rollback tran

А если это не удается, то столбец с ошибками находится во второй половине. И мы продолжаем процесс, пока не найдем надоедливую колонку.

Что-нибудь более элегантное, чем это?

Примечание: я также нашел почти дубликат этого вопроса, но он едва отвечает на него.

Ответы [ 5 ]

6 голосов
/ 08 сентября 2010

Следующий скрипт создаст SELECT операторы для каждого целочисленного столбца Basetable.
Выполнение результирующих SELECT операторов должно точно определить ошибочные столбцы в вашем Usertable.

SELECT  'PRINT ''' 
        + sc.Name 
        + '''; SELECT MIN(CAST(' 
        + sc.Name 
        + ' AS INTEGER)) FROM Usertable'
FROM    sys.columns sc 
        INNER JOIN sys.types st ON st.system_type_id = sc.system_type_id
WHERE   OBJECT_NAME(Object_ID) = 'BaseTable'
        AND st.name = 'INT'
0 голосов
/ 25 февраля 2016

Я принял подход Ливена Кирсмейкера, но расширил его. Если таблица имеет различную числовую длину поля, этот скрипт изменит приведение на основе имени типа и точности. Кредит все еще идет в Ливен для размышления об этом решении - оно мне очень помогло.

DECLARE @tableName VARCHAR(100)

SET @tableName = 'tableName'

SELECT 'PRINT ''' + sc.NAME + '''; SELECT MIN(CAST([' + sc.NAME + '] as ' + CASE 
        WHEN st.NAME = 'int'
            THEN 'int'
        ELSE st.NAME + '(' + cast(sc.precision AS VARCHAR(5)) + ',' + cast(sc.scale AS VARCHAR(5)) + ')'
        END + ')) from ' + @tableName
FROM sys.columns sc
INNER JOIN sys.types st ON st.system_type_id = sc.system_type_id
WHERE OBJECT_NAME(Object_ID) = @tableName
    AND st.NAME NOT IN ('nvarchar', 'varchar', 'image', 'datetime', 'smalldatetime', 'char', 'nchar')
0 голосов
/ 08 сентября 2010

Если это просто то, что вы запускаете вручную, то в зависимости от того, сколько данных вы вставляете, вы можете использовать предложение OUTPUT для вывода вставленных строк клиенту.

Строка после последнейто есть вывод должен быть тем, у которого проблема.

0 голосов
/ 08 сентября 2010

Я думаю, что вы выбрали неправильный подход. Если вы получаете арифметическое переполнение, просто выбирая столбцы из одной таблицы и вставляя их в другую, то вы должны выбирать из больших столбцов (например, bigint) и вставлять в маленькие столбцы (например, int). Это в корне неверно, и вам нужно изменить структуру вашей БД, чтобы вставка строк из одной таблицы в другую работала. Осмотрите каждый столбец из каждой таблицы и посмотрите, где можно получить переполнение, затем настройте таблицу назначения так, чтобы вставляемые вами данные соответствовали.

Я все еще думаю, что моя точка зрения верна, но в ответ на ваши комментарии, если вы хотите быстрое и грязное решение. Сделайте все свои столбцы в BaseTable varchar (MAX).

Тогда:

insert into BaseTable (c1,c2,...,cN)
select CAST(c1 AS varchar(max)),CAST(c2 AS varchar(max))...,cN 
from UserTable
0 голосов
/ 08 сентября 2010

Во многих случаях предложенный вами метод грубой силы является наилучшим.

Однако, если у вас есть копия базы данных, вы также можете публиковать поддельные данные.

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

Я делаю это, и это убирает все, что в моем коде вызывает проблему.

Вам нужно получить сгенерированную копию запроса, где вы можете скопировать ее и вставить в инструмент запросов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...