Где условие критерия в представлении, вызывающее ошибку - PullRequest
0 голосов
/ 20 мая 2011

У меня есть вид, который разбивает список с разделителями.Например, если у вас есть следующая таблица со следующими двумя столбцами:

ABC, A;B;C

Принимая имя «TestView», вы получите следующее:

Label  Source
--------------
ABC    A
ABC    B
ABC    C

Код получен изздесь: Разделение одного столбца на несколько строк

Когда я пытаюсь поместить условие в предложение where в представлении, я получаю сообщение об ошибке.Msgstr "Неверный параметр длины, переданный в функцию LEFT или SUBSTRING."Так что что-то вроде «select * from TestView, где Source = 'A'» вызовет эту ошибку.

Вот код из представления:

CREATE VIEW [dbo].[TestView]
AS
WITH L0 AS (SELECT 1 AS c 
            UNION ALL 
            SELECT 1),
     L1 AS (SELECT 1 AS c 
               FROM L0 AS A, 
                    L0 AS B),
     L2 AS (SELECT 1 AS c 
              FROM L1 AS A, 
                   L1 AS B),
     L3 AS (SELECT 1 AS c 
              FROM L2 AS A, 
                   L2 AS B),
     --counts up to 256
     Numbers AS (SELECT ROW_NUMBER() OVER (ORDER BY c) AS n 
                   FROM L3)
SELECT Label,        
       LTRIM(RTRIM(SUBSTRING(valueTable.Sources, nums.n, charindex(N';', valueTable.Sources + N';', nums.n) - nums.n))) AS Source
  FROM Numbers AS nums 
  JOIN dbo.SourceTable AS valueTable ON nums.n <= CONVERT(int, LEN(valueTable.Sources)) 
                                    AND SUBSTRING(N';' + valueTable.Sources, n, 1) = N';'

Ответы [ 2 ]

1 голос
/ 21 мая 2011

По этой ссылке вы предоставляете ссылки на другую статью (http://www.sqlservercentral.com/articles/Tally+Table/72993/), которая предоставляет довольно эффективную функцию сплиттера.

Вы можете попробовать использовать это вместо

CREATE FUNCTION dbo.DelimitedSplit8K
--===== Define I/O parameters
    (@pString VARCHAR(8000), @pDelimiter CHAR(1))
RETURNS TABLE WITH SCHEMABINDING AS
 RETURN
--===== "Inline" CTE Driven "Tally Table" produces values from 0 up to 10,000...
 -- enough to cover VARCHAR(8000)
  WITH E1(N) AS (
             SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
             SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
             SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
            ),                          --10E+1 or 10 rows
   E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
   E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
 cteTally(N) AS (--==== This provides the "zero base" and limits the number of rows right up front
                 -- for both a performance gain and prevention of accidental "overruns"
             SELECT 0 UNION ALL
             SELECT TOP (DATALENGTH(ISNULL(@pString,1))) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
            ),
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)
             SELECT t.N+1
               FROM cteTally t
              WHERE (SUBSTRING(@pString,t.N,1) = @pDelimiter OR t.N = 0) 
            )
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.
 SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY s.N1),
    Item       =    SUBSTRING(@pString,s.N1,ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,8000))
   FROM cteStart s
;

Тогда это будет случай

with rawData (Label,rawString) as (select 'ABC','A;B;C')

select Label,Item From rawData
Cross Apply DelimitedSplit8K(rawData.rawString, ';')
WHERE Item = 'A'
1 голос
/ 20 мая 2011

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

Узнайте, каков результат этого фрагмента для каждой записи: charindex (N ';', valueTable.Sources + N';', nums.n) - nums.n

Держу пари, что charindex возвращает 0, указывая, что не может найти это значение, а nums.n больше 0.

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