Sql server SQL Server:不使用临时表替换字符串中与字符不同的字符
我在表中有一个nvarhar10列。它可以存储任何类型的UNICODE字符串 我想用“0”替换每个与“1”不同的字符 假设我有字符串“012345C18*”。我应该得到“01000000100” 我设法使用一个helper表来实现它,该表包含从1到我的第10列大小的索引, 像这样: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
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。