SQL Server:用一个单词替换多个单词

时间:2017-01-03 09:52:39

标签: sql-server database sql-server-2008

我有一个带有Event列的SQL Server表,其中包含如下值:

[Event]
----------------------------------------
Payment stopped, Claim, Claim, Claim
Claim
Claim, Claim, Claim
Claim, Claim, Payment stopped, Case Closed

现在,用户想要查看此列,其中包含“Claim”一词的摘要计数,以便下面的列看起来像

[Event]
-------------------------------------
Payment stopped, 3 Claims
Claim
3 Claims
2 Claims, Payment stopped, Case Closed

“索赔”一词最多可出现400次,他们不介意将计数保留在价值的起点(3个索赔,付款停止)或价值结束(付款停止,3个索赔)。我有一个可以得到这个单词的udf,但删除逗号,空格似乎真的很难。

有没有办法做到这一点(有或没有udf)?我正在使用SQL Server 2008。

4 个答案:

答案 0 :(得分:1)

首先,您需要使用拆分功能按ID拆分项目,并获取每个项目的计数。之后我们需要结果。以下是带有样本数据的查询。

declare @myevent table(id int identity,name varchar(max));

insert into @myevent select 'Payment stopped, Claim, Claim, Claim';
insert into @myevent select 'Claim';
insert into @myevent select 'Claim, Claim, Claim';
insert into @myevent select 'Claim, Claim, Payment stopped, Case Closed';

with cte as(
    select id,cast(count(item) over(partition by id,ltrim(rtrim(item))) as varchar(5)) + ' ' + ltrim(rtrim(item)) Item
    from @myevent
        cross apply dbo.Split(name,',')
)
,cte1 as(
    select distinct id,item
    from cte
)
select distinct id
        ,substring((select ','+item
                    from cte1 c1
                    where c1.id = c2.id
                    order by id
                    for xml path('')
                    )
                    , 2, 1000
                ) [result]
from cte1 c2

以下是拆分功能

CREATE FUNCTION [dbo].[Split] (
      @InputString VARCHAR(8000),
      @Delimiter VARCHAR(50)
)

RETURNS @Items TABLE (
      Item VARCHAR(8000)
)

AS
BEGIN
      IF @Delimiter = ' '
      BEGIN
            SET @Delimiter = ','
            SET @InputString = REPLACE(@InputString, ' ', @Delimiter)
      END

      IF (@Delimiter IS NULL OR @Delimiter = '')
            SET @Delimiter = ','

      DECLARE @Item VARCHAR(8000)
      DECLARE @ItemList VARCHAR(8000)
      DECLARE @DelimIndex INT

      SET @ItemList = @InputString
      SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
      WHILE (@DelimIndex != 0)
      BEGIN
            SET @Item = SUBSTRING(@ItemList, 0, @DelimIndex)
            INSERT INTO @Items VALUES (@Item)

            -- Set @ItemList = @ItemList minus one less item
            SET @ItemList = SUBSTRING(@ItemList, @DelimIndex+1, LEN(@ItemList)-@DelimIndex)
            SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
      END -- End WHILE

      IF @Item IS NOT NULL -- At least one delimiter was encountered in @InputString
      BEGIN
            SET @Item = @ItemList
            INSERT INTO @Items VALUES (@Item)
      END

      -- No delimiters were encountered in @InputString, so just return @InputString
      ELSE INSERT INTO @Items VALUES (@InputString)

      RETURN

END -- End Function

输出

id  result
1   1 Payment stopped,3 Claim
2   1 Claim
3   3 Claim
4   1 Case Closed,1 Payment stopped,2 Claim,2 Claim

答案 1 :(得分:1)

尝试以下脚本

DECLARE @V_WORD NVARCHAR(10)    =   'Claim'

DECLARE @TABLE  TABLE
(   [Event] NVARCHAR(MAX))

INSERT INTO @TABLE
VALUES('Payment stopped, Claim, Claim, Claim'),('Claim'),('Claim, Claim, Claim'),('Claim, Claim, Payment stopped, Case Closed')

;WITH CTE
AS  (
        SELECT  [Event]
                ,CHARINDEX(@V_WORD,[Event],0)   [stpos]
                ,(LEN([Event]) - LEN(REPLACE([Event],@V_WORD,''))) / LEN(@V_WORD)   AS  [ECount]
        FROM    @TABLE
)

SELECT  REPLACE([Event]
                ,SUBSTRING([Event],[stpos],([ECount] * LEN(@V_WORD)) + (([ECount]-1) * 2))
                ,CAST([ECount] AS NVARCHAR) +' Claim' +
                    (CASE WHEN [ECount] > 1 THEN 's' ELSE '' END) 
                )   [Result]
FROM    CTE

结果:

Payment stopped, 3 Claims
1 Claim
3 Claims
2 Claims, Payment stopped, Case Closed

答案 2 :(得分:0)

我同意其他评论者的意见,您应该真正查看导入过程和数据模式,以将所有不同的事件保存为单个表行。

但是,如果无法做到这一点,您可以相对简单地进行所需的操作,而无需使用#if DEBUG Console.WriteLine("Debug"); #else Console.WriteLine("Release"); #endif 或其他功能。请注意,除了cte这个词之外的其他任何内容都不会有效,因为这就是您在问题中所要求的所有内容:

Claim

输出:

declare @Event table(Event nvarchar(500));
insert into @Event values
 ('Payment stopped, Claim, Claim, Claim')
,('Claim')
,('Claim, Claim, Claim')
,('Claim, Claim, Payment stopped, Case Closed')
,('Payment stopped, Case Closed');

select Event
        ,case (len(Event) - len(replace(Event,'Claim','')))/5
                    when 0 then ''
                    when 1 then '1 Claim' + case when len(replace(Event,'Claim','')) > 0 then ', ' else '' end
                    else cast((len(Event) - len(replace(Event,'Claim','')))/5 as nvarchar(5)) + ' Claims' + case when len(replace(Event,'Claim','')) > 0 then ', ' else '' end
                 end
            + case when len(replace(Event,'Claim','')) > 0
                    then replace(replace(replace(Event,', Claim',''),'Claim, ',''),'Claim','')
                    else ''
                    end as Result
from @Event;

答案 3 :(得分:0)

另一种方法是执行此操作的标量函数。

您问题中的架构。

CREATE TABLE #Event (EVENT_LIST VARCHAR(MAX))

INSERT INTO #Event
SELECT 'Payment stopped, Claim, Claim, Claim'
UNION ALL
SELECT 'Claim'
UNION ALL
SELECT 'Claim, Claim, Claim'
UNION ALL
SELECT 'Claim, Claim, Payment stopped, Case Closed'

您需要为每个记录计算每个单词。因此需要创建一个每行执行一次并给出结果的函数。

逻辑功能:

CREATE FUNCTION [dbo].FN_REPEAT_COUNT(@VAR VARCHAR(MAX))
RETURNS VARCHAR(MAX)
AS
BEGIN

 SET @VAR=@VAR+','
;WITH CTE AS  --Recursive CTE for calculating ',' indexes
(
    SELECT 1 INDX_FRM 
    , LEN(@VAR) LEN_VAR
    , CHARINDEX(',',@VAR)+1 AS INDX_TO

    UNION ALL

    SELECT CAST(INDX_TO+1 AS INT)
    , LEN_VAR
    , CHARINDEX(',',SUBSTRING(@VAR,INDX_TO+1,LEN_VAR))+INDX_TO+1 

    FROM CTE WHERE INDX_TO<LEN_VAR
)
,CTE2 AS(    --cte to generate records based on ',' index
SELECT  SUBSTRING(@VAR,INDX_FRM,INDX_TO-INDX_FRM-1 ) AS LIST FROM CTE
)
,CTE3 AS (  --cte for count of word Claim and making them back to column
SELECT (
        SELECT CAST(COUNT(CASE 
                        WHEN LIST = 'Claim'
                            THEN 1
                        ELSE NULL
                        END) AS VARCHAR(2)) + ' ' + LIST + ','
        FROM CTE2
        GROUP BY LIST
        FOR XML PATH('')
        ) COUNTED

)  
--Removing 0 and replacing ',' with Empty String
SELECT @VAR = REPLACE( SUBSTRING(COUNTED,1,LEN(COUNTED)-1),'0','') FROM CTE3
RETURN @VAR
END

现在只需在列上调用Scalar函数,如下所示

SELECT *, dbo.FN_REPEAT_COUNT(EVENT_LIST) AS FN_RES FROM #Event

输出

╔════════════════════════════════════════════╦═══════════════════════════════════════╗
║                 EVENT_LIST                 ║                FN_RES                 ║
╠════════════════════════════════════════════╬═══════════════════════════════════════╣
║ Payment stopped, Claim, Claim, Claim       ║ 3 Claim, Payment stopped              ║
║ Claim                                      ║ 1 Claim                               ║
║ Claim, Claim, Claim                        ║ 3 Claim                               ║
║ Claim, Claim, Payment stopped, Case Closed ║  Case Closed,2 Claim, Payment stopped ║
╚════════════════════════════════════════════╩═══════════════════════════════════════╝
相关问题