SQL Server несколько ЗАМЕНИТЬ с помощью таблицы #temp

Я пытаюсь ЗАМЕНИТЬ несколько символов в запросе SQL Server и хочу достичь этого с помощью таблицы #temp вместо вложенного REPLACE. Я получил код SQL ниже и хочу достичь результата, например

ABC
DEF
GHI

IF OBJECT_ID('tempdb..#temp') IS NOT NULL DROP TABLE #temp
IF OBJECT_ID('tempdb..#temp2') IS NOT NULL DROP TABLE #temp2

CREATE TABLE #temp
(
    STRING_TO_REPLACE NVARCHAR(5)
)
INSERT INTO #temp (STRING_TO_REPLACE)
VALUES            (' ')
                 ,('/')
                 ,('_') 

CREATE TABLE #temp2
(
    STRING_NAME NVARCHAR(5)
)

INSERT INTO #temp2 (STRING_NAME)
VALUES            ('A BC')
                 ,('D/EF')
                 ,('G_HI')

SELECT REPLACE(t2.STRING_NAME,(SELECT t1.STRING_TO_REPLACE   
                               FROM #temp t1),'') 
 FROM #temp2 t2

IF OBJECT_ID('tempdb..#temp') IS NOT NULL DROP TABLE #temp
IF OBJECT_ID('tempdb..#temp2') IS NOT NULL DROP TABLE #temp2

Я могу добиться результата с вложенной заменой

SELECT REPLACE(REPLACE(REPLACE(t2.STRING_NAME,'_',''),'/',''),' ','')  FROM #temp2 t2

но очень хотелось бы сделать это через таблицу #temp. Пожалуйста, помогите мне в этом. Когда я пытаюсь запустить свой первый код, я получаю следующую ошибку:

Msg 512, уровень 16, состояние 1, строка 23 Подзапрос возвращает более 1 стоимость. Это недопустимо, когда подзапрос следует =,! =, <, < =,

>= или когда подзапрос используется как выражение.

Ответ 1

Вот один из способов: CROSS APPLY

SELECT result 
FROM   #temp2 t2 
       CROSS apply (SELECT Replace(string_name, t1.string_to_replace, '') AS 
                           result 
                    FROM   #temp t1) cs 
WHERE  result <> string_name 

Результат:

result
-----
ABC
DEF
GHI

Примечание: Это будет работать, только если каждый string_name имеет только один string_to_replace

Обновление: Чтобы обрабатывать более одного string_to_replace в одном string_name, это один из способов: Dynamic sql

Я сделал небольшое изменение в таблице #temp, добавив свойство identity в цикл

IF Object_id('tempdb..#temp') IS NOT NULL 
  DROP TABLE #temp 

IF Object_id('tempdb..#temp2') IS NOT NULL 
  DROP TABLE #temp2 

CREATE TABLE #temp 
  ( 
     id                INT IDENTITY(1, 1), 
     string_to_replace NVARCHAR(5) 
  ) 

INSERT INTO #temp 
            (string_to_replace) 
VALUES      (' '), 
            ('/'), 
            ('_') 

CREATE TABLE #temp2 
  ( 
     string_name NVARCHAR(5) 
  ) 

INSERT INTO #temp2 
            (string_name) 
VALUES      ('A BC'), 
            ('D/EF'), 
            ('G_HI'), 
            ('A BD_') 

DECLARE @col_list          VARCHAR(8000)= '', 
        @sql               VARCHAR(max), 
        @cntr              INT, 
        @inr               INT =1, 
        @STRING_TO_REPLACE NVARCHAR(5) 

SELECT @cntr = Max(id) 
FROM   #temp 

SET @sql = 'select ' 

WHILE @inr < = @cntr 
  BEGIN 
      SELECT @STRING_TO_REPLACE = string_to_replace 
      FROM   #temp 
      WHERE  id = @inr 

      IF @inr = 1 
        SET @col_list = 'replace (STRING_NAME,''' 
                        + @STRING_TO_REPLACE + ''','''')' 
      ELSE 
        SET @col_list = 'replace (' + @col_list + ',''' 
                        + @STRING_TO_REPLACE + ''','''')' 

      SET @inr+=1 
  END 

SET @sql += ' from #temp2' 
--print @col_list 
SET @sql = 'select ' + @col_list + ' as Result from #temp2' 

--print @sql 
EXEC (@sql) 

Результат:

Result
------
ABC
DEF
GHI
ABD

Ответ 2

Многократная замена может быть достигнута с помощью рекурсивного CTE в следующем примере:

IF OBJECT_ID('tempdb..#temp') IS NOT NULL DROP TABLE #temp
IF OBJECT_ID('tempdb..#temp2') IS NOT NULL DROP TABLE #temp2

CREATE TABLE #temp
(
    STRING_TO_REPLACE NVARCHAR(10)
    ,Pattern NVARCHAR(10)
)
INSERT INTO #temp (STRING_TO_REPLACE, Pattern)
VALUES            (' ', '% %')
                 ,('/', '%/%')
                 ,('_', '%[_]%') ;

CREATE TABLE #temp2
(
    STRING_NAME NVARCHAR(10)
);

INSERT INTO #temp2 (STRING_NAME)
VALUES            ('A BC')
                 ,('D/EF_F E')
                 ,('G_HI')
                 ,('XYZ');

WITH CTE_Replace AS
(
    SELECT   STRING_NAME AS OriginalString
            ,CAST(STRING_NAME AS NVARCHAR(10)) AS ReplacedString
            ,CAST('' AS NVARCHAR(10)) AS StringToReplace
            ,1 AS ReplaceCount
    FROM    #temp2 ancor
    UNION ALL
    SELECT   CTE_Replace.OriginalString
            ,CAST(REPLACE(CTE_Replace.ReplacedString, rep.STRING_TO_REPLACE, '') AS NVARCHAR(10)) AS ReplacedString 
            ,CAST(rep.STRING_TO_REPLACE AS NVARCHAR(10)) AS StringToReplace
            ,CTE_Replace.ReplaceCount + 1 AS ReplaceCount
    FROM    #temp rep
    INNER JOIN CTE_Replace ON CTE_Replace.ReplacedString LIKE rep.Pattern
)
,CTE_FinalReplacedString AS
(
    SELECT  OriginalString
            ,ReplacedString
            ,ReplaceCount
            ,ROW_NUMBER() OVER (PARTITION BY OriginalString ORDER BY ReplaceCount DESC) AS [Rank]
    FROM    CTE_Replace
)
SELECT *
FROM    CTE_FinalReplacedString
WHERE   [Rank] = 1

Обратите внимание, что таблица #temp была обновлена, чтобы включить дополнительный столбец с именем Pattern, этот столбец содержит шаблон поиска, который будет использоваться для поиска конкретных строк, которые необходимо заменить. Это также было сделано для упрощения утверждения объединения в рекурсивном CTE. Также обратите внимание, что для поиска символа _ шаблон поиска должен был быть обновлен как '%[_]%'. Причина этого в том, что SQL Server интерпретирует символ _ как дикий символ вместо определенного символа, который мы пытаемся найти.

Ответ 3

заменить в таблице, вероятно, проще здесь

update t2 
set t2.string_name = Replace(t2.string_name, t1.string_to_replace, '')
from       #temp2 t2 
cross join #temp1 t1 

Ответ 4

Другой способ с рекурсивным CTE (полная партия ниже):

--Create a sample table, you should use YourTable
CREATE TABLE #temp2 (
    STRING_NAME NVARCHAR(max)
)

INSERT INTO #temp2 (STRING_NAME)
VALUES ('A BC'),('D/EF'),('G_HI'),('J_K/L_'),('MNO')
--I add some more objects here

Основной запрос:

;WITH replacement AS (
SELECT *
FROM (VALUES (' '),('/'),('_')
) as t(STRING_TO_REPLACE)
), cte AS (
SELECT  STRING_NAME,
        STRING_NAME as OriginalString,
        ROW_NUMBER() OVER (ORDER BY STRING_NAME) as rn,
        1 as [Level]
FROM #temp2 t2
UNION ALL
SELECT  REPLACE(c.STRING_NAME,t.STRING_TO_REPLACE,'~'),
        c.OriginalString,
        c.rn,
        [Level]+1
FROM cte c
INNER JOIN replacement t
    ON CHARINDEX(t.STRING_TO_REPLACE,c.STRING_NAME,0) > 0
)

SELECT TOP 1 WITH TIES  OriginalString,
                        STRING_NAME
FROM cte 
ORDER BY ROW_NUMBER() OVER (PARTITION BY rn ORDER BY [Level] DESC)
OPTION (MAXRECURSION 0)

Вывод:

OriginalString  STRING_NAME
A BC            A~BC
D/EF            D~EF
J_K/L_          J~K~L~
G_HI            G~HI
MNO             MNO

Ответ 5

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

-- remove all non-aplphabetical characters
SELECT NewString FROM #temp2 CROSS APPLY dbo.PatExclude8K(STRING_NAME,'[^A-Z]');
-- remove all spaces, forward slashes and underscores
SELECT NewString FROM #temp2 CROSS APPLY dbo.PatExclude8K(STRING_NAME,'[ /_]');

Оба запроса создают этот результирующий набор:

NewString
------------
ABC
DEF
GHI

Ответ 6

Я нашел ниже код в stackoverflow, который кажется более близким к тому, что я пытаюсь достичь, но боюсь, что как я могу использовать его с моим кодом

    declare @String varchar(max) = '(N_100-(6858)*(6858)*N_100/0_2)%N_35'

        --table containing values to be replaced
        create table #Replace 
        (
            StringToReplace varchar(100) not null primary key clustered
            ,ReplacementString varchar(100) not null    
        )

        insert into #Replace (StringToReplace, ReplacementString)
        values ('+', '~')
            ,('-', '~')
            ,('*', '~')
            ,('/', '~')
            ,('%', '~')
            ,('(', '~')
            ,(')', '~')

        select @String = replace(@String, StringToReplace, ReplacementString)
        from #Replace a

        select @String

        drop table #Replace

ИЗМЕНИТЬ по gofr1

CREATE FUNCTION replacement
(
    @String nvarchar(max)
)
RETURNS nvarchar(max) 
AS
BEGIN

    DECLARE @Replace TABLE (
        StringToReplace nvarchar(100),
        ReplacementString nvarchar(100)
    )

    INSERT INTO @Replace (StringToReplace, ReplacementString)
    VALUES ('+', '~')
        ,('-', '~')
        ,('*', '~')
        ,('/', '~')
        ,('%', '~')
        ,('(', '~')
        ,(')', '~')

    SELECT @String = replace(@String, StringToReplace, ReplacementString)
    FROM @Replace

    RETURN @String

END
GO

Затем назовите его:

SELECT dbo.replacement ('A B-C/d')

Вывод:

A B~C~d