2014-10-17 2 views
6

테이블에 NVARCHAR(10) 열이 있습니다. 모든 유형의 UNICODE 문자열을 저장할 수 있습니다.SQL Server : 임시 테이블이없는 문자열에서 char과 다른 문자를 대체하십시오.

'1'과 다른 모든 문자를 '0'으로 바꾸고 싶습니다.

문자열 'C18 *'이 있다고 가정 해 봅시다. 나는 '0100000100'을 얻어야한다.

는이 같은 내 칼럼 (10), 의 크기에 1 인덱스를 포함하는 도우미 테이블을 사용하여 수행 할 관리 :

CREATE TABLE HELP(Idx INT) 
INSERT INTO HELP 
    SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT  7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10 

DECLARE @myStr VARCHAR(10) 
SET @myStr = 'C18*' 

SELECT STUFF((SELECT '' + CASE(B.Ch) WHEN '1' THEN '1' ELSE '0' END FROM (
    SELECT SUBSTRING(A.Val,H.Idx,1) AS Ch 
    FROM 
    (SELECT @myStr AS Val) A 
    CROSS JOIN HELP H 
)B FOR XML PATH('')),1,0,'') 

그것은 작동하지만, 그것이 더 좋은 수행 할 수 있습니다 방법? 이것은 칼럼의 크기가 시간이 지남에 따라 변할 수 있다는 사실을 무시하고 단순한 업데이트에서는보기 흉한 것처럼 보입니다. 또한 SQL> = 2005에서 실행해야합니다.

SQL 바이올린here

감사합니다!

+0

에서 테스트를 또는 .Net 프로 시저를 사용할 수 있습니까? 데이터를 여러 번 실행하거나 데이터를 한 번만 실행해야하는 작업입니까? –

+0

@MauriceReeves 수십 개의 큰 테이블 (10K + 행)에 대해 한 번만 실행해야합니다 (일부 데이터베이스에서는 손상된 데이터가 일부만 있음). 간단한 콘솔 응용 프로그램이 이것을 해결했을 것입니다,하지만 같은 상황이 다시 발생한다면 + 나는 그 임시 테이블을 좋아하지 않습니다. – darkdante

+2

숫자 테이블은 매우 유용합니다. 많은 사람들이 그것을 영구 테이블로 가지고 있습니다. –

답변

5

여기에 cte로 이것을 수행하는 방법이 있습니다. 내 시스템에서는 실제로 뷰 이름으로 cteTally가 있습니다. 이 기술은 읽기가 0 인 10,000 행 뷰를 생성합니다. ;) 게시 된 코드가 잘 작동합니다. 이 예제에서는 실제 시스템에서 작업하고있는 문자열을 테이블로 옮겼습니다.

declare @myStrings table(MyVal varchar(10)); 

insert @myStrings 
select 'C18*'; 

WITH 
    E1(N) AS (select 1 from 
    (
     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))dt(n)), 
    E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows 
    E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max 
    cteTally(N) AS 
    (
     SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4 
    ) 

SELECT STUFF((SELECT '' + CASE(B.Ch) WHEN '1' THEN '1' ELSE '0' END FROM (
    SELECT SUBSTRING(A.MyVal, t.N, 1) AS Ch 
    FROM 
    @myStrings A 
    CROSS JOIN cteTally t 
    where t.N < LEN(a.MyVal) 
)B FOR XML PATH('')),1,0,'') 
+1

SQL 2005에서 작동하려면 약간의 수정이 필요했습니다. 2008 년에는 값 (1), (1), (1), (1), (1), (1)), (1), (1), (1)을 사용하십시오. : D –

+0

방금 ​​기술을 사용하여 숫자보기를 만들었습니다. 감사합니다 :) – darkdante

+0

명시 적 ORDER BY없이 하위 쿼리의 행 순서에 의존 할 수 있습니까? –

1

전체 테이블을 업데이트하려면 UDF가 유용 할 수 있습니다.

Create FUNCTION dbo.F_MakeBinary(@Param NVarchar(max)) 
RETURNS NVarchar (max) 
AS 
BEGIN  
DECLARE @a NVarchar(max) 
Set @[email protected] 
While PATINDEX(N'%[^0-1]%', @a) > 0 
begin  
    select @a=STUFF(@a, PATINDEX(N'%[^0-1]%', @a),1,'0') 
end 
Return @a 
END 

사용법 :

Update aTable Set aField = dbo.F_MakeBinary(aField) 
7

약간 다른 접근, 재귀 쿼리 사용 : 한 표준 PROC이 할 수

WITH cte AS 
    (SELECT v, i = 0, 
     nv = CAST('' AS NVARCHAR(10)) 
    FROM t 
    UNION ALL 
    SELECT v, i+1, 
     CAST(nv + CASE WHEN SUBSTRING(v, i+1, 1) = '1' THEN '1' ELSE '0' END 
      AS NVARCHAR(10)) 
    FROM cte 
    WHERE i+1 <= LEN(v) 
) 
SELECT v, nv 
FROM cte 
WHERE i = LEN(v) ; 

SQLFiddle