在SQL字符串中查找信息

时间:2014-02-12 17:18:32

标签: sql-server tsql

我有一个查询(sql-server),我试图从字符串中提取信息 该表有3个字段(Key1 =订单号,datestamp =仅限日期,logtext = string)。

我想要的是字符串中的key1,datestamp和info。我需要一些数据,包括“Sales Reps:”(例如:“Sales Reps:DSCANTL1 - > BDENNIK1”)。我在查询中显示的“salesreps”列中有我需要的内容,但是如果在logtext列中出现多个“Sales Reps”的情况,我也想显示每个。 我还希望在“Sales Reps:”之前第一次出现时间戳(##:##:##),以及在该时间戳之前的rep的名称。
正如我的数据所示,有时在“销售代表:”之前没有时间戳,有时则有一个时间戳。

以下是表格中数据的示例。

Key1    datestamp               logtext
337316  2013-01-15 00:00:00.000 JWebb   10:41:19 Sales Reps: ARCHITE1 -> BDENNIK1
338644  2013-01-28 00:00:00.000 TWert    10:21:26 Sales Reps: PHEISSE1 -> PHEISSE2
305699  2013-08-23 00:00:00.000 JDickey  11:24:27 Status: no -> yesJDickey  11:25:03 SalesReps:  -> NOREP JDickey  11:25:08 Status: yes -> no
360429  2014-02-10 00:00:00.000 TThomas  15:51:01 Need By: 02/20/14 -> 02/14/14 Ship By: 02/20/14 -> 02/14/14 BOatman  15:53:27 Sales Reps: TCONNOR1 -> TCONNOR1~DSIDES1
347094  2013-07-12 00:00:00.000 LLilley  10:58:07 Amount: 864 -> 876.5 Order Amount: 864 -> 876.5 LLilley  10:58:08 Total Number Releases: 2 -> 3 Total Number Releases: 3 -> 4 Sales Reps: BBARBER -> LDODGE1
337319  2013-01-15 00:00:00.000 JWebb   10:25:20 Sales Reps: ARCHITE1 -> BDENNIK1 Sales Reps: BDENNIK1 -> ARCHITE1 338524   2013-01-28 00:00:00.000 TLong    12:01:54 Sales Reps: DESIGNM1-> SPARTAN1 LLilley  11:59:07 Sales Reps: SPARTAN1 -> TKELLEY1

以下是我的查询内容:

2014年2月14日更新:

    ;WITH cteChanges as
(
select      Key1, DateStamp
            ,logtext
            ,Substring(logtext,PATINDEX('%Sales Reps:%',logtext),35) salesreps
            ,Substring(logtext,PATINDEX('%New Record%',logtext),10) newOrNot
            ,(len(logtext) - len(replace(logtext,'Sales Reps:',''))) / LEN('Sales Reps:') cnt
            ,REVERSE(SUBSTRING(REVERSE(substring(REPLACE(Logtext, CHAR(10), '|'),0,PATINDEX('%Sales Reps:%',logtext)))
                    ,CHARINDEX('|',REVERSE(substring(REPLACE(Logtext, CHAR(10), '|'),0,PATINDEX('%Sales Reps:%',logtext)+1))),8)) ChangeTime
            ,SUBSTRING(REVERSE(LEFT(REVERSE(substring(REPLACE(Logtext, CHAR(10), '|'),0,PATINDEX('%Sales Reps:%',logtext)))
                    ,CHARINDEX('||',REVERSE(substring(REPLACE(Logtext, CHAR(10), '|'),0,PATINDEX('%Sales Reps:%',logtext))))-1)),0,10) ChangePerson

FROM        chglog (nolock)

WHERE       identifier = 'OrderHed' and company ='EII' and tablename = 'OrderHed'
            and Logtext like '%Sales Reps:%'
            and Datestamp >= '01/01/2013'
            and rtrim(Left(LogText,9)) <> 'manager'

            --and Substring(logtext,PATINDEX('%New Record%',logtext),10) <> 'New Record'
)

SELECT      Key1 OrderNum
            ,DateStamp
            --,logtext
            ,SUBSTRING(salesreps,1,PATINDEX('%-%',salesreps)) + Substring(salesreps,PATINDEX('%>%',salesreps)
                    ,CASE WHEN (convert(int,charINDEX(char(10),Substring(salesreps,PATINDEX('%>%',salesreps),10))-1)) < 0 THEN 10 ELSE 
                    (charINDEX(char(10),Substring(salesreps,PATINDEX('%>%',salesreps),10))-1) END ) salesreps
            ,ChangePerson
            ,ChangeTime
            ,cnt TimesSalesPersonChanged
            --,newOrNot

FROM        cteChanges

ORDER BY    DateStamp, Key1

1 个答案:

答案 0 :(得分:0)

我能够修改您的查询,使其将Sales Reps条目作为单独的行返回(至少是以时间戳为前缀的那些行)。

这应该会让你走上正轨。我调试此功能的能力有限,因为我没有原始形式的数据(或架构),但它应该解决您最初使用CTE看到第一个“销售代表”条目时遇到的问题。

要使其运行,您首先需要创建此功能:

 create function dbo.SplitString 
    (
        @str nvarchar(4000), 
        @separator char(1)
    )
    returns table
    AS
    return (
        with tokens(p, a, b) AS (
            select 
                1, 
                1, 
                charindex(@separator, @str)
            union all
            select
                p + 1, 
                b + 1, 
                charindex(@separator, @str, b + 1)
            from tokens
            where b > 0
        )
        select
            p-1 zeroBasedOccurance,
            substring(
                @str, 
                a, 
                case when b > 0 then b-a ELSE 4000 end) 
            AS s
        from tokens
      )
    GO

然后,这是你的查询的新版本(我评论并删除了你在这里的一些原始内容,因为有些列丢失了,其中一些是抛出错误,但这很可能是因为我的测试架构中的差异)。

    ;WITH cteChanges as
(
select      l.Key1, l.DateStamp
            ,l.logtext
            ,Substring(m.S,PATINDEX('%Sales Reps:%',m.S),35) salesreps
            ,Substring(m.S,PATINDEX('%New Record%',m.S),10) newOrNot
            ,(len(m.S) - len(replace(m.S,'Sales Reps:',''))) / LEN('Sales Reps:') cnt
            ,REVERSE(SUBSTRING(REVERSE(substring(REPLACE(m.S, CHAR(10), '|'),0,PATINDEX('%Sales Reps:%',m.S)))
                    ,CHARINDEX('|',REVERSE(substring(REPLACE(m.S, CHAR(10), '|'),0,PATINDEX('%Sales Reps:%',m.S)+1))),8)) ChangeTime
            ,SUBSTRING(REVERSE(LEFT(REVERSE(substring(REPLACE(m.S, CHAR(10), '|'),0,PATINDEX('%Sales Reps:%',m.S)))
                    ,CHARINDEX('||',REVERSE(substring(REPLACE(m.S, CHAR(10), '|'),0,PATINDEX('%Sales Reps:%',m.S))))-1)),0,10) ChangePerson

FROM        chglog (nolock) l
  cross apply dbo.SplitString(replace(l.logtext, char(13), ''), char(10)) m
WHERE       m.S like '%Sales Reps:%'

            --and Substring(logtext,PATINDEX('%New Record%',logtext),10) <> 'New Record'
)

SELECT      Key1 OrderNum
            ,DateStamp
            ,logtext
            ,SUBSTRING(salesreps,1,PATINDEX('%-%',salesreps)) + Substring(salesreps,PATINDEX('%>%',salesreps)
                    ,CASE WHEN (convert(int,charINDEX(char(10),Substring(salesreps,PATINDEX('%>%',salesreps),10))-1)) < 0 THEN 10 ELSE 
                    (charINDEX(char(10),Substring(salesreps,PATINDEX('%>%',salesreps),10))-1) END ) salesreps
            --,ChangePerson
            --,ChangeTime
            --,cnt TimesSalesPersonChanged
            --,newOrNot

FROM        cteChanges

ORDER BY    DateStamp, Key1

我的主要更改是在其中添加CROSS APPLY子句,以根据行终止符将字符串拆分为单独的行。

在此处查看完整的SQLFiddle:http://sqlfiddle.com/#!3/f8a67/11

此外,请参阅此处,了解我原来尝试以不同的方式(可能更简单?)方式:http://sqlfiddle.com/#!6/a5940/3