问题描述
我使用sql Server 2012,但遇到一个问题:我无法更新状态以匹配签名密钥带有星号*
的字符。
我需要更新状态以匹配以签名密钥为例的字符
Signature Key Group Id Portion Key Status
*$*$**s$***$**$**$* 3 12s Match Characters
上面签名密钥中的组ID 3是** s必须等于部分密钥(12s),因此状态必须是匹配字符。
但是如果组ID值是** f且部分密钥值是15g,则它将为不匹配字符状态
因为g
不等于f
。
Create table #Ref
(
SignatureKey nvarchar(50),GroupId int,PortionKey nvarchar(50),Status nvarchar(100)
)
insert into #Ref (SignatureKey,GroupId,PortionKey,status)
values ('*$*$C$***$**$**$*',3,'s',NULL),('*$*$*$FG$*$**$*',4,'F',('*$*$*$***$*$D$*',6,'D',('*$t**$*$***$***$**$*',2,'t12',('*$**$*$***$**t$**$*',5,'12t',NULL)
update r
set r.Status = 'Not Match Charachters'
from #Ref r
cross apply
dbo.Split(r.SignatureKey,'$') f where CAST (r.GroupId AS INT) = f.Id and r.PortionKey <> f.Data
预期结果:
Signature Key Group Id Portion Key Status
*$*$C$***$**$**$* 3 s Not Match Characters
*$*$*$FG$*$**$* 4 F Not Match Characters
*$*$*$***$*$D$* 6 D Not Match Characters
*$t**$*$***$***$**$* 2 t12 Match Characters
*$**$*$***$**t$**$* 5 12t Match Characters
在签名密钥值等于部分密钥的情况下,我要说的是状态为匹配字符
恰好是(c = c)或签名密钥在组ID上都有星号,因此我将忽略开始*并进行比较
字符为(* f = 1f)的字符表示如果我有星星,则忽略与字符比较。
最后更新的帖子:
dbo.split function exist on
https://www.sqlteam.com/forums/topic.asp?TOPIC_ID=50648
组ID也代表签名密钥中的部分编号 假设我有签名密钥;
*$*c$C$**$***$5*$6*
然后从左到右:
组ID 1值= *
组ID 2值= * c
组ID 3值= c
group id 4 value = **
群组ID 5值= ***
群组ID 6值= 5 *
群组ID 7值= 6 *
解决方法
样本数据
**$Global:MySQLConnection.Open()
$query1 = 'SELECT * FROM wp_woocommerce_order_items WHERE order_id = 25696 '
$queryResults = Invoke-MySqlQuery -Query $query1 -Verbose
Foreach($query in $queryResults){
$listbox1.Items.Add($query)
$Global:MySQLConnection.close()
}
}**
解决方案
下面的解决方案没有采用您链接的declare @data table
(
Exa int,-- example number (for result sorting purposes only)
Sig nvarchar(20),-- signature key
Grp int,-- group id
Prt nvarchar(5) -- portion key
);
insert into @data (Exa,Sig,Grp,Prt) values
(1,'*$*$C$***$**$**$*',3,'s' ),(2,'*$*$*$FG$*$**$*',4,'F' ),(3,'*$*$*$***$*$D$*',6,'D' ),(4,'*$t**$*$***$***$**$*',2,'t12'),(5,'*$**$*$***$**t$**$*',5,'12t');
函数,而是基于this StackOverflow answer来分割字符串。将答案应用于样本数据将得出:
split()
对于with cte as (
select d.Sig,1 as Starts,charindex('$',d.Sig) as Pos
from @data d
union all
select cte.Sig,cte.Pos + 1,cte.Sig,cte.Pos + 1)
from cte
where Pos > 0
)
select cte.Sig,cte.Starts,cte.Pos,substring(cte.Sig,case when cte.Pos > 0 then cte.Pos - cte.Starts else len(cte.Sig) end) as Token
from cte
order by cte.Sig,cte.Starts;
,这将产生以下结果:
*$*$*$***$*$D$*
要在此基础上进一步建立解决方案,需要:
- 上述分段的行号,以检索在
Sig Starts Pos Token -------------------- ----------- ----------- -------------------- *$*$*$***$*$D$* 1 2 * *$*$*$***$*$D$* 3 4 * *$*$*$***$*$D$* 5 6 * *$*$*$***$*$D$* 7 10 *** *$*$*$***$*$D$* 11 12 * *$*$*$***$*$D$* 13 14 D *$*$*$***$*$D$* 15 0 *
中指定的Token
。Grp
函数在这里起作用。 - 当
row_number()
包含通配符时,将Token
与Prt
匹配的方法。我使用了递归公用表表达式来拆分Token
和Token
来检查匹配字符的数量是否等于非通配符的数量。
这给了我
outer apply
哪个会产生:
with cte as -- recursive CTE to parse d.Sig
(
select d.Sig,cte.Pos + 1)
from cte
where Pos > 0
),split as -- split cte.Sig based on parsing values
(
select cte.Sig,case when cte.Pos > 0 then cte.Pos - cte.Starts else len(cte.Sig) end) as Token,row_number() over(partition by cte.Sig order by cte.Starts) as Num
from cte
),tokenW as -- recursive CTE to parse d.Prt for s.Token with wildcard
(
select d.Sig,s.Token,1 as Pos,substring(s.Token,1,1) as PosChar
from @data d
join split s
on s.Sig = d.Sig
and s.Num = d.Grp
where charindex('*',s.Token) > 0
union all
select tw.Sig,tw.Token,tw.Pos+1,substring(tw.Token,1)
from tokenW tw
where tw.Pos < len(tw.Token)
)
select d.Sig,d.Grp,d.Prt,case
when d.Prt = s.Token then 'Match' -- match 100%
when len(replace(s.Token,'*','')) = c.Cnt then 'Match' -- match wildcard pattern
else 'No match'
end as [Status]
from @data d
join split s
on s.Sig = d.Sig
and s.Num = d.Grp
outer apply ( select count(1) as 'Cnt' -- count number of matching characters (not counting '*')
from tokenW tw
join split ss
on ss.Sig = tw.Sig
and ss.Token = tw.Token
where tw.Sig = d.Sig
and tw.PosChar <> '*'
and tw.PosChar = substring(d.Prt,tw.Pos,1) ) c
order by d.Exa;