2016-02-22 5 views
1

Я работаю с сторонним приложением, которому нужен альтернативный список имен для имен улиц. Разработчики предоставили сценарий Python, который будет генерировать список, но время, которое требуется для генерации, ужасно. То, что я пытаюсь сделать, это создать запрос или хранимую процедуру, которая создаст все различные комбинации имен улиц и сохранит JOINID для каждого имени. Вот как выглядит источник.SQL Server Комбинированный запрос

JOINID StreetName 
147  PAULSON RD 
165  NORTH AVE 
270  E SCHOOL RD 
212  OAKWOOD AVE 

Результаты будут выглядеть следующим образом:

JOINID StreetName 
147  PAULSON 
147  PAULSON RD 
165  NORTH 
165  NORTH AVE 
270  SCHOOL 
270  E SCHOOL 
270  SCHOOL RD 
270  E RD 
270  E SCHOOL RD 
212  OAKWOOD 
212  OAKWOOD AVE 

Результаты будут исключены такие значения, как один RD или другого типа дороги.

Это текущий запрос, с которым я работаю. Это возвращает список разделов с соответствующими ID

'SELECT   
    JOINID, Split.a.value('.', 'VARCHAR(100)') AS Streetname 
    FROM 
    SELECT JOINID, CAST('<M>' + REPLACE([StreetName], ' ', '</M><M>') + </M>' 
    AS XML) AS CVS FROM [L].[ROADCENTERLINESHF]) AS A CROSS APPLY 
    CVS.nodes('/M') AS Split(a)` 

Любые предложения были бы замечательными. Спасибо

+0

Что вы уже пробовали? –

+0

Получение всех возможных перестановок не будет быстрым, особенно если есть много данных. Вам нужно определить некоторые бизнес-правила, о каких перестановках вы хотите исключить. Я заметил, что вы включили NORTH из 165, но исключили E из 270. Я подозреваю, что у вас будет довольно хороший список исключений (суд, ct, road, rd, rr, po, po, ave, avenue, st, street и т. Д. .) –

+0

У меня есть это, что дает мне список разделов с соответствующими идентификаторами. 'SELECT JOINID, Split.a.value ('. ',' VARCHAR (100) ') AS Имя улицы FROM (SELECT JOINID, CAST (' '+ REPLACE ([StreetName],' ',' ') + '' AS XML) AS CVS FROM [L]. [ROADCENTERLINESHF]) КАК КРОСС ПРИМЕНЯТЬ CVS.nodes ('/ M') AS Split (a) '@ Shachaf.Gortler – broncosbuck99

ответ

0

Вы можете начать с функции, которая разбивает каждую строку на таблицу/список значений и ординалов. Затем из этих результатов вставьте все значения в таблицу temp и начните свой запрос из этой таблицы.

CREATE function [dbo].[Split](
@String nvarchar (max), 
@Delimiter nvarchar (200) 
) 
returns @ValueTable table (
    [id] int IDENTITY(0,1), 
    [Value] nvarchar(max) 
) 
begin 
declare @NextString nvarchar(max) 
declare @Pos int 
declare @NextPos int 
declare @CommaCheck nvarchar(1) 

--Initialize 
set @NextString = '' 
set @CommaCheck = right(@String,1) 

--Check for trailing Comma, if not exists, INSERT 
--if (@CommaCheck <> @Delimiter) 
set @String = @String + @Delimiter 

--Get position of first Comma 
set @Pos = charindex(@Delimiter,@String) 
set @NextPos = 1 

--Loop while there is still a comma in the String of levels 
while (@pos <> 0) 
begin 
    set @NextString = substring(@String,1,@Pos - 1) 

    insert into @ValueTable ([Value]) Values (@NextString) 

    set @String = substring(@String,@pos +1,len(@String)) 

    set @NextPos = @Pos 
    set @pos = charindex(@Delimiter,@String) 
end 

return 
end 

Здесь представлена ​​версия функции разделения моментов, упомянутая в комментариях, которая также включает в себя порядковый номер. `

--select * from dbo.SplitStrings_Moden('The quick brown fox jumped over the lazy dog.', ' ', 0) 
--select * from dbo.SplitStrings_Moden('The quick brown fox jumped over the lazy dog.', ' ', 1) 
CREATE FUNCTION dbo.SplitStrings_Moden 
(
    @List NVARCHAR(MAX), 
    @Delimiter NVARCHAR(255), 
    @RemoveEmptyEntries BIT = 1 
) 
RETURNS TABLE 
WITH SCHEMABINDING AS 
RETURN 
    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), 
     E2(N)  AS (SELECT 1 FROM E1 a, E1 b), 
     E4(N)  AS (SELECT 1 FROM E2 a, E2 b), 
     E42(N)  AS (SELECT 1 FROM E4 a, E2 b), 
     cteTally(N) AS (SELECT 0 UNION ALL SELECT TOP (DATALENGTH(ISNULL(@List,1))) 
         ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E42), 
     cteStart(N1) AS (SELECT t.N+1 FROM cteTally t 
         WHERE (SUBSTRING(@List,t.N,1) = @Delimiter OR t.N = 0)) 
    SELECT Item = SUBSTRING(@List, s.N1, ISNULL(NULLIF(CHARINDEX(@Delimiter,@List,s.N1),0)-s.N1,8000)), ROW_NUMBER() OVER (ORDER BY N1) ordinal 
    FROM cteStart s 
    WHERE (SUBSTRING(@List, s.N1, ISNULL(NULLIF(CHARINDEX(@Delimiter,@List,s.N1),0)-s.N1,8000)) <> '' 
      OR 
      @RemoveEmptyEntries = 0 
     ); 

`

+2

Пожалуйста, не используйте циклы для разделения строк. Это невероятно неэффективно. Вот несколько других сплиттеров, которые будут работать намного лучше, чем это. http://sqlperformance.com/2012/07/t-sql-queries/split-strings –

+0

UGH. Я регулярно использую сплиттер Moden, но Аарон должен был изменить его для своей статьи, и производительность ужасна, когда список с разделителями равен nvarchar (max). Оригинальную статью Джеффа Модена можно найти здесь. http://www.sqlservercentral.com/articles/Tally+Table/72993/ –