2016-10-04 6 views
10

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

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, Level 16, State 1, Line 23 подзапрос возвращает более чем на 1 значение. Это не допускается, когда подзапрос следует =,! =, <, < =,

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

+0

Вы пытаетесь генерировать вложенные выбрать динамически или вы пытаетесь произвести 3 (в данном случае) выберите инструкции, которые выполняются последовательно , (или что-то еще) – paulbarbin

+0

Я в основном пытаюсь заменить '', '/', '_', если все или любые из них существуют в строке в любой ячейке столбца – kami

ответ

5

Вот один из способов использования 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

Update: Для обработки более чем один 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 
+1

Проблемы, которые я думаю для значений с несколькими разделителями. –

+0

@AlexK. В образцах данных каждая строка имеет одно слово 'string_to_replace'. В вопросе запроса OP находится функция 'replace' из-за' sub-query' –

+0

Prdp - ваш код - это код, но что, если мне нужно заменить несколько символов в одной строке. Например, если строка A/B_C, то как я могу сделать ABC? – kami

0

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

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

К сожалению, он не работает :( – gofr1

+0

Какая ошибка? – Paparazzi

+0

Ошибка при запуске этого обновления, а затем 'SELECT * FROM # temp2' он только менял первый символ из '# temp' (удаляет пробелы) – gofr1

1

многократной замены может быть достигнута с помощью рекурсивного 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 будет интерпретировать символ _ как дикий символ вместо определенного персонажа, который мы пытаемся найти.

+0

Сначала я написал что-то подобное, но потом я помню, что' _' означает \t * Любой отдельный символ. * для LIKE и поместите там CHARINDEX, который работает отлично, нет необходимости в 2 CTE. +1 от меня. – gofr1

+0

@ gofr1 Я не думал о CHARINDEX - определенно лучший вариант :) –

0

Другой способ с рекурсивной КТР (полный пакетный ниже):

--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 
+0

Ваше решение тоже хорошо. – kami

+0

Насколько я понимаю, вам нужно обновить столбец таблицы. Для этого вам нужно заменить некоторые символы. Я тебя понимаю? – gofr1

+0

Ну, это не совсем обновление. В принципе у меня уже есть таблица, в которой один из столбцов имеет ссылочные строки. В этих строках есть всевозможные символы, которые появляются разными пользователями, такими как «», «_», «/», «\», «-» и т. Д.В моем запросе мне нужно показать этот столбец другим столбцом, который будет измененным видом исходного столбца. Поэтому в измененном столбце я должен был очистить ссылочную строку без каких-либо из этих символов, о которых я упоминал выше. – kami

0

Простой способ справиться с этим, для загрузки копии 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 
0

Я нашел ниже код на 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 

EDIT по 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 
+0

Это решение работает только для одной строки, поэтому вам нужно ввести ее в действие. – gofr1

+0

Я добавляю пример на ваш вопрос – gofr1

+0

@ gofr1 - это это просто здорово, но проблема только в том, что я получил ТОЛЬКО ЧИТАТЬ доступ к серверу и не разрешил создавать ФУНКЦИИ. Есть ли какая-нибудь вещь, создающая ВРЕМЕННЫЕ ФУНКЦИИ? – kami

Смежные вопросы