Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server SQL Server:不使用临时表替换字符串中与字符不同的字符_Sql Server_Replace_Char_Difference_Chars - Fatal编程技术网

Sql server SQL Server:不使用临时表替换字符串中与字符不同的字符

Sql server SQL Server:不使用临时表替换字符串中与字符不同的字符,sql-server,replace,char,difference,chars,Sql Server,Replace,Char,Difference,Chars,我在表中有一个nvarhar10列。它可以存储任何类型的UNICODE字符串 我想用“0”替换每个与“1”不同的字符 假设我有字符串“012345C18*”。我应该得到“01000000100” 我设法使用一个helper表来实现它,该表包含从1到我的第10列大小的索引, 像这样: CREATE TABLE HELP(Idx INT) INSERT INTO HELP SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION

我在表中有一个nvarhar10列。它可以存储任何类型的UNICODE字符串

我想用“0”替换每个与“1”不同的字符

假设我有字符串“012345C18*”。我应该得到“01000000100”

我设法使用一个helper表来实现它,该表包含从1到我的第10列大小的索引, 像这样:

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 = '012345C18*'

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小提琴


谢谢

以下是一种使用cte的方法。在我的系统中,我实际上将CTE作为视图名称cteTally。此技术生成一个10000行的视图,读取次数为零;您发布的代码运行得很好。对于本例,我将字符串移动到一个表中,因为这是您在实际系统中使用的

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

insert @myStrings
select '012345C18*';

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,'')

如果要更新整个表,UDF可能很有用

Create FUNCTION dbo.F_MakeBinary(@Param NVarchar(max))
RETURNS NVarchar (max)
AS
BEGIN     
 DECLARE @a NVarchar(max)
 Set @a=@Param
 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)   

使用递归查询的方法略有不同:

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) ;

中测试,您只能使用标准过程或.Net过程执行此操作吗?这是需要多次运行还是只运行一次才能清除数据?@MauriceReeves它只需针对几十个大表10K+行运行两个数据库中的一些损坏数据一次。一个简单的控制台应用程序就可以解决这个问题,但我问如果同样的情况再次发生,我不喜欢临时表。数字表非常有用。很多人把它作为一个永久性的表,为了使用SQL2005,我不得不稍微修改我的cte。在2008+中,您可以将其更改为值1,1,1,1,1,1,1,1,而不是所有选择项:我刚刚用你的技术创建了我的数字视图!谢谢:在没有明确的order BY的情况下,您能依赖子查询中的行顺序吗?对不起,这里当然有很多子查询。我指的是XML子查询。您将字符与它连接在一起,假定它们的顺序正确,但您没有使用order BY。