SQL-запрос для замены символов путем получения списка записей из другой таблицы - PullRequest
0 голосов
/ 08 мая 2018

Я написал следующий запрос, чтобы взять идентификатор в качестве ввода, получить DocumentID из таблицы вложений, а затем использовать этот идентификатор для получения имени документа из таблицы Document. Как только я получаю имя документа, я удаляю все, кроме символов a-z и цифр. Приведенный ниже запрос работает нормально, если только один идентификатор документа возвращается на основе идентификатора объекта, как я могу заставить его работать, если один идентификатор объекта возвращает более одного идентификатора документа. Мне также нужно вернуть все эти новые имена.

ALTER PROCEDURE [dbo].[NormalizeDocumentFileName1] 
    -- Add the parameters for the stored procedure here
    @id nvarchar(16),
    @temp varchar(50) OUTPUT
AS
BEGIN

  Select @temp=Document.TheName from Document where id = (Select DocumentId from Attachment where EntityId = @id)
  Declare @KeepValues as varchar(50)
  Set @KeepValues = '%[^a-z0-9-_.]%'
  While PatIndex(@KeepValues, @temp) > 0
  Set @temp = Stuff(@temp, PatIndex(@KeepValues, @temp), 1, '')
   
END 

Ответы [ 3 ]

0 голосов
/ 08 мая 2018

Лично я бы пошел с совершенно другим подходом к этому. Я собираюсь использовать Алан Бурштейн NGrams8K .

Вы хотите избежать цикла WHILE, он будет работать ужасно и использовать подход с набором данных. Я собираюсь использовать функцию вместо:

CREATE FUNCTION NormalizeDocumentFileName (@FileName varchar(50) )
RETURNS TABLE
AS RETURN

    WITH Tokens AS (
        SELECT *
        FROM dbo.NGrams8k (@FileName,1) --If you didn't create the function on the dbo schema, you'll need to change it.
        WHERE token NOT LIKE '%[^a-z0-9-_.]%')
    SELECT CONVERT(varchar(50),(SELECT Token + '' 
                                FROM Tokens
                                ORDER BY Position
                                FOR XML PATH(''))) AS NormalFileName;
GO

Тогда вы можете сделать что-то простое, как:

SELECT D.YourColumn, NDFN.NormalFileName
FROM Document D
     CROSS APPLY NormalizeDocumentFileName(D.TheName) NDFN;
0 голосов
/ 08 мая 2018

Другая основанная на множестве функция для этого типа вещей - PatExclude8K функция делает то же самое, что и Ларну, и может использоваться повторно.Вы должны использовать ссылку, чтобы получить код T-SQL для создания функции.Функция работает следующим образом:

DECLARE @string varchar(50) = '$$$123___!!!555.ABC???';

SELECT * FROM dbo.patexclude8k(@string, '[^A-Za-z0-9-_.]');

Возвращает:

NewString
------------
123___555.ABC

Обратите внимание, что то, что LARNU соберет вместе, вернет ссылки на сущности для символов XML, таких как "&", ">" и т. Д.Но он будет работать лучше, чем Patexclude.Если вы не ожидаете обработки специальных символов XML, вы можете использовать слегка измененную версию, которая будет работать относительно одинаково - вот она:

CREATE FUNCTION dbo.PatExclude8K_NXP
(
    @String VARCHAR(8000),
    @Pattern VARCHAR(50)
) 
/*******************************************************************************
 Purpose:
 Given a string (@String) and a pattern (@Pattern) of characters to remove, 
 remove the patterned characters from the string.

Usage:
--===== Basic Syntax Example
 SELECT CleanedString 
 FROM dbo.PatExclude8K_NXP(@String,@Pattern);

--===== Remove all but Alpha characters
 SELECT CleanedString 
 FROM dbo.SomeTable st
 CROSS APPLY dbo.PatExclude8K(st.SomeString,'%[^A-Za-z]%');

--===== Remove all but Numeric digits
 SELECT CleanedString
 FROM dbo.SomeTable st
 CROSS APPLY dbo.PatExclude8K(st.SomeString,'%[^0-9]%');

 Programmer Notes:
 1. @Pattern is case sensitive (the function can be easily modified to make it so)
 2. There is no need to include the "%" before and/or after your pattern since since we 
    are evaluating each character individually

 Revision History:
 Rev 00 - 20180508 Initial Development - Alan Burstein

*******************************************************************************/
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
WITH
E1(N) AS (SELECT N FROM (VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) AS X(N)),
itally(N) AS 
(
  SELECT TOP(CONVERT(INT,LEN(@String),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
  FROM E1 T1 CROSS JOIN E1 T2 CROSS JOIN E1 T3 CROSS JOIN E1 T4
) 
SELECT NewString =
(
  SELECT SUBSTRING(@String,N,1)
  FROM iTally
  WHERE 0 = PATINDEX(@Pattern,SUBSTRING(@String COLLATE Latin1_General_BIN,N,1))
  FOR XML PATH('')
);

Наконец, и NGrams8K, и PatExclude работают немного лучше, когдаоптимизатор выбирает план параллельного выполнения.Чтобы форсировать параллельный план, вы можете использовать Make_parallel от Адама Мачаника.Используя в качестве примера решение Ларну, вы могли бы создать параллельный план следующим образом:

SELECT D.YourColumn, NDFN.NormalFileName
FROM Document D
     CROSS APPLY NormalizeDocumentFileName(D.TheName) NDFN;
     CROSS APPLY dbo.make_parallel();
0 голосов
/ 08 мая 2018

Хммм. Вы можете обойтись без цикла while и использовать рекурсивный CTE:

with cte as (
      Select d.TheName, 0 as lev, d.TheName as orig_TheName
      from Document d
      where d.id = (Select DocumentId from Attachment where EntityId = @id)
      union all
      select Stuff(cte.thename, PatIndex(@KeepValues, cte.thename), 1, '') as DocumentId lev + 1, cte.orig_TheName
      from cte
      where PatIndex(@KeepValues, cte.thename) > 0
     )
select theName
from (select theName, max(lev) over (partition by orig_thename) as max_lev
      from cte
     ) x
where lev = max_lev
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...