2010-09-08 16 views
7

Wyobraź sobie stół z setką różnych kolumn. Wyobraź sobie, że mam tabelę danych użytkownika, z której chcę skopiować dane do tabeli podstawowej. Napisałem więc tę prostą instrukcję typu "wybierz-wybierz" i pojawia się ten błąd. Jaki jest najbardziej elegancki sposób, aby dowiedzieć się, która kolumna podnosi błąd?Jak ustalić, która kolumna podnosi błąd przepełnienia arytmetycznego po wstawieniu?

Moje pierwsze myśli na rozwiązania są o owijając go w transakcji, która będę ostatecznie wstecz oraz wykorzystać rodzaj dziel i rządź podejścia:

begin tran 

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

rollback tran 

I to oczywiście nie. Więc dzielimy kolumnę na pół tak, jak to:

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 

A jeśli się nie powiedzie, to w drugiej połowie kolumna z błędami. I kontynuujemy ten proces, dopóki nie znajdziemy brzydkiej kolumny.

Coś bardziej eleganckiego niż to?

Uwaga: Znalazłem również prawie duplikat tego pytania, ale ledwie odpowiada.

+0

Jeśli możesz dopasować typy danych UserTable do tych z BaseTable, twój insert nie powinien mieć żadnego problemu. Wszystko, co jest potrzebne, po znalezieniu obraźliwej kolumny * UserTable * . –

+0

@Lieven Cóż, UserTable jest po prostu ... tabelą użytkownika bez żadnych ograniczeń, ponieważ dane w niej zawarte pochodzą z Excela lub Accessa lub z innego. –

+0

Współczuję. Jeśli jest to coś, co należy zrobić regularnie, czy nie mógłbyś stworzyć skryptu/procedury przechowywanej, która sprawdza twoje dane wejściowe? Makro i prosty wybór mogłyby przejść długą drogę, coś jak "SELECT" c1 ", CAST (c1) AS INTEGER z UserTable". –

Odpowiedz

6

następujący skrypt stworzy SELECT oświadczenia dla każdej kolumny liczbą całkowitą Basetable.
Wykonanie wynikowych instrukcji SELECT powinno wskazać niepoprawne kolumny w twoim 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

Wow, podoba mi się to podejście. –

-1

Wiele razy sugerowana metoda brute force jest najlepszym sposobem.

Jednakże, jeśli masz kopię bazy danych, możesz również publikować fałszywe dane.

uruchom kwerendę, aby nie mieć o transkacji ukrywanie kolumny, która go łamie. Czasem w błędzie daje wskazówkę co do tego, co jest. Zwykle, jeśli patrzysz na to, co się dzieje, możesz zobaczyć, kiedy tekst przechodzi w int lub odwrotnie.

Robię to, a to powoduje odebranie czegokolwiek w moim kodzie powodując problem.

Należy uzyskać kopię wygenerowanego zapytania, które można skopiować i wkleić w narzędziu do wysyłania zapytań.

+0

Tak, mówi: Przepełnienie arytmetyczne w varbinary o wartości 1239847234.000000. Lub coś takiego. Zdecydowanie mogę przeczytać komunikat o błędzie, ale to w żaden sposób mi nie pomoże. –

+0

A więc wszystkie wartości, które wyciągasz z varcharu i wszystko, co wkładasz do varcharu? ponieważ odmiana powoduje, że myślę, że to nieprawda. –

+0

Kolumny w TableTable i UserTable są tym samym innymi słowami? –

-1

Sądzę, że stosujesz niewłaściwe podejście. Jeśli otrzymujesz arytmetyczne przepełnienie, po prostu wybierając kolumny z jednej tabeli i wstawiając do innej, musisz wybierać z większych kolimnów (np. Bigint) i wstawiać do małych kolumn (np. Int). Jest to zasadniczo niepoprawne działanie i trzeba zmienić strukturę DB, aby wstawianie wierszy z jednej tabeli do drugiej działało. Sprawdź każdą kolumnę z każdej tabeli i zobacz, gdzie można uzyskać nadmiar, a następnie dostosuj tabelę docelową, aby dopasować wstawiane dane.

Nadal uważam, że mój punkt widzenia jest ważny, ale w odpowiedzi na twoje uwagi, jeśli chcesz szybkie i brudne rozwiązanie. Stwórz wszystkie swoje kolumny w bazie danych BaseTable varchar (MAX).

Następnie:

insert into BaseTable (c1,c2,...,cN) 
select CAST(c1 AS varchar(max)),CAST(c2 AS varchar(max))...,cN 
from UserTable 
+2

Nie, nie widzę żadnej wady w moim podejściu. Nie mam kontroli nad UserTable i wszystkie kolumny w nim są varchar. Chcę tylko szybki i brudny sposób, aby dowiedzieć się, która kolumna powoduje błąd. To tylko początkowe ładowanie danych i nie powinno to zająć dużo czasu na sprawdzenie tego czy tamtego. Wiesz co mam na myśli? –

+1

I to nie odpowiada na moje pytanie, to unikanie. –

+0

Wszystkie kolumny są varchar? Wszyscy? –

0

Jeśli jest to po prostu coś jest uruchomiony ręcznie, a następnie w zależności od ilości danych wstawiasz można użyć klauzuli OUTPUT do wyjścia wstawione wiersze do klienta.

Wiersz po ostatnim, który jest wyprowadzany, powinien być wierszem, w którym wystąpił problem.

+0

Powiedzmy, że mam tylko jeden wiersz z dużą ilością kolumn. :) –

+0

Następnie wystarczy spojrzeć na jeden rząd. – Sam

+2

@Sam, brakuje ci punktu. Nie ilość wierszy jest problematyczna, ale liczba kolumn. –

0

Wziąłem podejście Lieven Keersmaekers, ale rozszerzyłem go. Jeśli tabela ma różne długości pola liczbowego, ten skrypt zmieni Cast na podstawie nazwy typu i precyzji. Kredyt nadal należy do Lieven za myślenie o tym rozwiązaniu - bardzo mi to pomogło.

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') 
Powiązane problemy