2011-08-25 25 views
5

Mamy SQL, który wykonuje funkcję CAST (do FLOAT) na ColumnA. SQL ma filtr, który na koniec pośrednio odfiltruje te wiersze, które mają wartości inne niż liczbowe w kolumnie A. Jednak ze względu na to, co moim zdaniem wynika z działania części SQL w równolegle, uważam, że CAST jest nawet stosowane do wierszy, które są filtrowane i to powoduje, że SQL nie powiedzie się "nie można oddać wartości jako float ... "nie można rzutować wartości jako float

wiem, że jeśli będę biegać z jednego proc dodając wskazówkę zapytania

OPTION (MAXDOP 1) 

że SQL działa jako oczekiwane. Podejrzewam, że uruchomienie 1 proc powoduje, że filtr zostanie zastosowany do wygaszenia wiersza z wartościami nieliczbowymi w kolumnie A, aby CASTING jego wartości się powiódł. Uważam również, że stosując wskazówkę zapytaniu

OPTION (FORCE ORDER) 

rozwiązuje problem, jestem zakładając becausethis też zapewnia, że ​​filtr jest stosowany pierwszy i uzyskać znacznie lepszą wydajność kwerendy, że jedna działa na jednym cylindrze.

Jestem opiekunem, który naprawia problem za pomocą drugiej opcji. Jeśli mam jakieś nieporozumienia dotyczące tego, co się tu dzieje, lub jeśli ktoś chciałby wyjaśnić moje ogólne zrozumienie lub zalecenie, byłbym wdzięczny.

używam na

Microsoft SQL Server 2008 R2 (RTM) - 10.50.1720.0 (X64) 12 czerwca 2010 01:34:59 Copyright (c) Microsoft Corporation Enterprise Edition (64- bit) w systemie Windows NT 5.2 (Build 3790: Service pack 2)

namyśle:

wydaje się, że byłoby miło, T-SQL miał następujące funkcje sprawdzić, jeśli ciąg mógł być przenośnym przywrócone do określonego typu danych.

IsFloat IsNumeric IsInteger itp

naprawdę jestem zły na ile kolumn wszelkiego rodzaju danych, które mi się znaleźć w naszej bazie danych, które są zdefiniowane jako varchar (255). Myślę, że rozwiązaniem jest "nie robić tego!"

+2

Czy możesz pokazać kod SQL? – MatBailie

+1

Prosi nas, abyśmy pomogli naprawić samochód, nie zauważając samochodu. Pokaż nam samochód. – JNK

+0

T-SQL ma IsNumeric – MatBailie

Odpowiedz

4

Odnośnie twojej refleksji.

Wydaje się, że byłoby miło, T-SQL miał następujące funkcje sprawdzić, czy ciąg znaków może być przekształcany do określonego typu danych.

Serwer SQL 2012 wprowadza do tej potrzeby TRY_CONVERT. Tak więc poniższe zapytanie zwróci wartość NULL zamiast błędu.

SELECT TRY_CONVERT (FLOAT, 'Fish') 

Nie ma gwarancji, nawet z seryjnymi planów, że klauzula WHERE nastąpią przed SELECT jest oceniany. Jak wyjaśnił in this blog post z SQL Server 2005, jest to bardziej prawdopodobne niż w poprzednich wersjach. The Behavior Changes to Database Engine Features in SQL Server 2005 w szczególności nazywa to w następujący sposób.

SQL Server 2005 czasami ocenia wyrażeń w kwerendach szybciej niż gdy są one oceniane w SQL Server 2000. To zachowanie zapewnia następujące ważne korzyści:

  • Możliwość dopasowania indeksów na kolumny obliczane na wyrażenia w zapytaniu, które są takie same jak wyliczone wyrażenie kolumny.
  • Zapobieganie redundantnym obliczeniom wyników wyrażenia.

Więcej dyskusji na temat tego problemu znajduje się w innym dobrym blogu Craig Freedman Conversion and Arithmetic Errors.

W wersjach sprzed 2012 r. I TRY_CONVERT należy zawinąć CAST AS FLOAT w oświadczeniu CASE. na przykład

SELECT CASE WHEN ISNUMERIC(Col)=1 THEN CAST(Col AS FLOAT) END AS Col 
    FROM Table 
    WHERE ISNUMERIC(Col)=1 

To nadal nie jest absolutnie gwarantowana aby zapobiec otrzymujesz błędy jak ISNUMERIC sama tylko sprawdza, że ​​wartość będzie oddane do jednego z typów danych liczbowych, a nie specjalnie się unosić An example of an input that would fail is '.'

CASE jest udokumentowane w większości zwarcie w książkach w Internecie (some exceptions are discussed here)

można również znaleźć dodatkowe dyskusja/skarg na ten temat w punkcie connect SQL Server should not raise illogical errors i good explanation of a similar issue przez SQLKiwi

1

Uważam, że masz rację. Funkcja CONVERT() jest stosowana zanim predykaty "pośrednio odfiltrowują" wiersze.

Aby uniknąć wyjątku, masz rację, jednym z podejść jest próba uzyskania pewnej kontroli nad kolejnością operacji w planie wykonania. Jeśli podpowiedź dla Ciebie działa, możesz to zrobić. (Osobiście wskazówki są dla mnie ostatecznością.)

Należy zauważyć, że SQL Server ma funkcję IsNumeric.

Funkcja IsNumeric jest nieco niewystarczająca, w tym sensie, że istnieją pewne wartości, które "przepuszczą" test IsNumeric, ale które podniosą wyjątek, gdy zostaną przekształcone na liczbowy typ danych.

Osobiście staram się iść z tym podejściem:

select convert(float,case when isnumeric(t.foo)=1 then t.foo else null end) 

zamiast poziomie instrukcji wskazówek.

Lub, chciałbym określić inne predykaty, które powinny "filtrować" wartości, które nie powinny być konwertowane.

select convert(float,case when t.fi in ('fo','fum') then t.foo else null end) 
Powiązane problemy