如何在SQL SELECT替换中使用通配符

时间:2017-04-18 23:50:58

标签: sql sql-server

我有一个名为Event的字段,它包含如下数据:

查看:

ID Event
1  2015-T4-C 
2  2015-G4-C
3  2015-T4-C; 2015-R4-C; 2015-Z4-C
4  2018-T4-C
5  2015-T4-Z

使用SQL SELECT(MSSQL)如何使用通配符替换字符串的通配符部分?

e.g。这是我想要做的虽然不起作用。替换的第一次出现是为了满足只有一个实例的值,第二次替换它以满足具有多个实例的值'; '在他们中:

SELECT
REPLACE(REPLACE(view.Event, '_____T___', ''), '_____T___; ', '')
FROM view

我要找的结果是:

查看结果

ID Event
1    
2  2015-G4-C
3  2015-R4-C; 2015-Z4-C
4  
5

谢谢

编辑:有多个'T'的实例,例如2017-T4-C,2018-T4-C,2019-T4-C,2015-T4-Z所以不能在'2015-T4-C'上使用替换

编辑2:

P.S。它就像这样开始

原始表

ID Event
1  2015-T4-C 
2  2015-G4-C
3  2015-T4-C 
3  2015-R4-C
3  2015-Z4-C
etc

然后我使用一个XML查询来将它们放在同一行上,例如。

3  2015-T4-C; 2015-R4-C; 2015-Z4-C

编辑3 - 现在我知道在SELECT中不可能使用通配符替换它会改变问题。我要找的结果是:

ID EventFilter1           EventFilter2
1                         2015-T4-C
2  2015-G4-C
3  2015-R4-C; 2015-Z4-C   2015-T4-C
4                         2018-T4-C
5                         2015-T4-Z

我可以回去以不同的方式从原始表中提取数据:

原始表

ID Event
1  2015-T4-C 
2  2015-G4-C
3  2015-T4-C 
3  2015-R4-C
3  2015-Z4-C
etc

编辑4:这是一个新的问题,知道不可能使用通配符:

您好

我有一个客户表,我有一个事件表。每个客户有多个事件。我需要导出到分号分隔的单行以进行外部系统导入,根据过滤器将结果拆分为两列。

活动表:

ID Event
1  2015-T4-C 
2  2015-G4-C
3  2015-T4-C 
3  2015-R4-C 
3  2015-Z4-C
4  2018-T4-C 
4  2018-T4-W
4  2018-K4-I
4  2018-Z4-W
5  2015-T4-Z

期望的结果:

ID EventFilter1(T)       EventFilter2(notT)
1  2015-T4-C
2                        2015-G4-C
3  2015-T4-C             2015-R4-C; 2015-Z4-C
4  2018-T4-C; 2018-T4-W  2018-K4-I; 2018-Z4-W    
5  2015-T4-Z 

目前我使用两个单独的连接但是只想使用一个简单并加速它。这是我现在所做的,我该如何简化呢?目标1是让它更快,目标2是让它更简单但更乐于支持速度而不是简单。

SELECT c.ID, e.EventFilter1(T), e2.EventFilter2(notT)
FROM Customers c
LEFT JOIN (SELECT 
           c.ID, 
           EventFilter1(T) = STUFF((
                  SELECT distinct '; ' + e.Event
                  FROM Events e
                  WHERE c.ID = e.ID AND Event like '%-T%'
                  FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
            FROM Customers c WHERE c.ID in (SELECT ID FROM Events)) as e
on c.ID = e.ID
LEFT JOIN (SELECT 
           c.ID, 
           EventFilter2(notT) = STUFF((
                  SELECT distinct '; ' + e2.Event
                  FROM Events e2
                  WHERE c.ID = e2.ID AND Event not like '%-T%'
                  FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
            FROM Customers c WHERE c.ID in (SELECT ID FROM Events)) as e2
on c.ID = e2.ID

那么有没有一种方法可以在连接子查询中提取没有过滤器的所有数据,然后在主查询中过滤并拆分它,或者我可以在一个子查询中拉出两组带有两个过滤器的数据? e.g:

LEFT JOIN (SELECT 
       c.ID, 
       EventFilter1(T) = STUFF((
              SELECT distinct '; ' + e.Event
              FROM Events e
              WHERE c.ID = e.ID AND Event like '%-T%'
              FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
      EventFilter2(notT) = STUFF(( **** What do I put here? ****
        FROM Customers c WHERE c.ID in (SELECT ID FROM Events)) as e
on c.ID = e.ID

4 个答案:

答案 0 :(得分:1)

借助CROSS APPLY和一点点XML作为拆分器

示例

Declare @YourTable table (ID int, [Event] varchar(500))
Insert Into @YourTable values
(1,  '2015-T4-C'), 
(2,  '2015-G4-C'),
(3,  '2015-T4-C; 2015-R4-C; 2015-Z4-C'),
(4,  '2018-T4-C'),
(5,  '2015-T4-Z')

Declare @Pattern varchar(100) = '_____T___'

Select A.ID
      ,NewVal =IsNull(B.S,'')
 From  @YourTable A
 Cross Apply (
                Select S = Stuff((Select '; ' +RetVal 
                  From (
                        Select RetSeq = Row_Number() over (Order By (Select null))
                              ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
                        From  (Select x = Cast('<x>' + replace((Select replace(A.[Event],';','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A 
                        Cross Apply x.nodes('x') AS B(i)
                       ) B1
                  Where PatIndex(@Pattern,RetVal)=0
                  Order by RetSeq
                  For XML Path ('')),1,2,'') 
             ) B

<强>返回

ID  NewVal
1   
2   2015-G4-C
3   2015-R4-C; 2015-Z4-C
4   
5   

答案 1 :(得分:0)

我认为原来的问题不完整...... 我们看到的数据是xml上的内容的结果,因此应该首先清理原始表以获得正确的结果。

请在下面找到针对tbevents的解决方案作为原始事件表。

create table #tbpattern(
myPat varchar(10) 
)

insert into #tbpattern
values ('T1'),('T2'),('T3'),('T4-C'),('T4-Z')

select * from #tbpattern


create table #tbevents
(
eventid varchar(1000) 
)


insert into #tbevents 
values ('2015-T4-C'),('2015-G4-C'),('2015-Z4-C'),('2018-T4-C'),('2015-T4-Z')


select e.eventid
from #tbevents e
where not exists
(
select 1 from #tbpattern p where charindex(p.myPat,e.eventid) > 0
)



drop table #tbpattern
drop table #tbevents
  

从上面的结果中应用STUFF

答案 2 :(得分:0)

你有固定长度的字符串。这确实为您提供了一些选择。这是一个相当痛苦的问题:

select (case when substr(t.event, 6, 1) = 'T'
             then stuff(t.event, 1, 11, '')
             when substr(t.event, 17, 1) = 'T'
             then stuff(t.event, 12, 11, '')
             when substr(t.event, 28, 1) = 'T'
             then stuff(t.event, 23, 11, '')
             . . .
         end)

这确实有一个缺点,即只删除一个。

答案 3 :(得分:0)

我添加了另一个答案,因为EDITS偏离了原来的问题

Declare @YourTable table (ID int, [Event] varchar(50))
Insert Into @YourTable values
(1  ,'2015-T4-C'), 
(2  ,'2015-G4-C'),
(3  ,'2015-T4-C'),
(3  ,'2015-R4-C'),
(3  ,'2015-Z4-C'),
(4  ,'2018-T4-C'), 
(4  ,'2018-T4-W'),
(4  ,'2018-K4-I'),
(4  ,'2018-Z4-W'),
(5  ,'2015-T4-Z')

Declare @Pattern varchar(100) = '_____T___' 

Select A.ID
      ,NewCol1 = IsNull(B.S,'')
      ,NewCol2 = IsNull(C.S,'')
 From  (Select Distinct ID from @YourTable) A
 Cross Apply (
               Select S = Stuff((Select Distinct '; ' +[Event] 
                 From @YourTable
                 Where PatIndex(@Pattern,[Event])=0
                    and ID = A.ID
                 For XML Path ('')),1,2,'') 
             ) B
 Cross Apply (
               Select S = Stuff((Select Distinct '; ' +[Event] 
                 From @YourTable
                 Where PatIndex(@Pattern,[Event])>0
                    and ID = A.ID
                 For XML Path ('')),1,2,'') 
             ) C

<强>返回

ID  NewCol1                 NewCol2
1                           2015-T4-C
2   2015-G4-C   
3   2015-R4-C; 2015-Z4-C    2015-T4-C
4   2018-K4-I; 2018-Z4-W    2018-T4-C; 2018-T4-W
5                           2015-T4-Z