使用#temp table

时间:2016-10-04 13:54:17

标签: sql sql-server tsql

我试图在SQL Server查询中替换多个字符,并希望通过#temp表而不是嵌套的REPLACE来实现。我在下面得到了SQL代码,想要实现像

这样的结果
  ABC 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   值。当子查询遵循=,!=,<,< =,

时,不允许这样做      
    

,> =或当子查询用作表达式时。

  

6 个答案:

答案 0 :(得分: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

时才会有效

更新:要在一个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 :(得分: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中的join语句。另请注意,为了找到_字符,搜索模式必须更新为'%[_]%'。这是因为SQL Server会将_字符解释为野生字符,而不是我们要查找的特定字符。

答案 2 :(得分:0)

表格中的替换可能更容易

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

答案 3 :(得分:0)

递归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

答案 4 :(得分: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

答案 5 :(得分: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
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