Mam funkcję, która dzieli ciąg znaków (wklejony na końcu dla jasności). Ta funkcja działa zgodnie z oczekiwaniami, gdy jest używana samodzielnie. Przykład:Dziwny błąd w udf, gdy jest zawarty w "WHERE ... IN" klauzula
SELECT value
FROM dbo.mg_fn_Split('2#1','#')
Zwraca
-- value --
-- 2 --
-- 1 --
-----------
Ale kiedy jest stosowany w "gdzie" klauzula, tak jak w tym przykładzie (więcej na TABLEA później):
SELECT * FROM TableA WHERE TableA.id IN
(
SELECT value
FROM dbo.mg_fn_Split('2#1','#')
)
otrzymuję błąd: "Niepoprawny parametr długości przekazywany do funkcji LEFT lub SUBSTRING."
Tabela A jest tutaj użyta jako przykład. Używanie różnych tabel (zakładając, że mają kolumnę id) czasami zwraca poprawne wyniki, podczas gdy na innych tabelach pojawia się błąd.
Zakładam, że ma to coś wspólnego z kolejnością wykonania, ale nadal nie widzę, co mogłoby "zepsuć" funkcję.
Szukam wyjaśnienia "co się dzieje", a nie "użyj tego zamiast". Wiem, że mogę używać sprzężeń na przykład, aby uzyskać wyniki.
Definicja funkcji:
-- Description: Returns a table containing the results of a string-split operation.
-- Params:
-- DelimitedList: The string to split
-- Delimiter: The delimiter char, defaults to ','
-- Columns:
-- Position - The char index of the item
-- Value - The actual item
-- =============================================
CREATE Function [dbo].[mg_fn_Split]
(
@DelimitedList nvarchar(max)
, @Delimiter nvarchar(2) = ','
)
RETURNS TABLE
AS
RETURN
(
With CorrectedList As
(
Select Case When Left(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '' End
+ @DelimitedList
+ Case When Right(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '' End
As List
, Len(@Delimiter) As DelimiterLen
)
, Numbers As
(
Select TOP(Coalesce(DataLength(@DelimitedList)/2,0)) Row_Number() Over (Order By c1.object_id) As Value
From sys.columns As c1
Cross Join sys.columns As c2
)
Select CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen As Position
, Substring (
CL.List
, CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen
, CharIndex(@Delimiter, CL.list, N.Value + 1)
- (CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen)
) As Value
From CorrectedList As CL
Cross Join Numbers As N
Where N.Value <= DataLength(CL.List)/2
And Substring(CL.List, N.Value, CL.DelimiterLen) = @Delimiter
)
EDIT: mam założyć skrzypce wykazują to: http://sqlfiddle.com/#!3/9f9ff/3
UDF wbudowane zostają rozszerzone na zapytanie, więc prawdopodobnie niektóre operacje łączenia lub filtry są oceniane w innej kolejności, jakiej się nie spodziewałeś. –
Jaki jest powód nieużywania połączeń? IMHO najlepiej jest zostawić parsowanie ciągów poleceń sql, jeśli to możliwe. –
Zgadzam się z komentarzem Martina, uważam, że twoja klauzula WHERE dla twojej funkcji jest podnoszona do twojego Select * z TableA. Jeśli skomentujesz następującą etykietę And Substring (CL.List, N.Value, CL.DelimiterLen) = @Delimiter w twojej funkcji, dostaniesz ten sam problem, który został wystawiony, spowodowany przez jedną z twoich wartości Substringów oceniających -1. –