2017-01-03 87 views
2

替换词多次出现我有一个SQL Server表包含这样值的列EventSQL服务器:一个

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

现在用户要查看此列具有摘要计数字的“声明”,使下面的柱看起来像

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

字的“声明”可能存在高达400倍,他们不介意保持计数价值的起点(3索赔,付款已停止)或价值结束(付款已停止,3个索赔)。我有一个udf,可以得到这个词的数量,但删除逗号,空格似乎非常困难。

有没有办法做到这一点(有或无UDF)?我使用SQL Server 2008的

+1

这似乎是一个工作的前沿,而不是分贝给我。分开一个csv,重新格式化它,和s将它重新组合在一起将成为带有SQL的PITA。 – Jamiec

+0

这是用于SSRS报告。您认为使用报告设计器中的选项可能是可行的吗? – Saranya

+1

可能的,但有可能的是正确设计你的表,所以它不是一个问题。包含您需要操作的逗号分隔值的列不是回退报表的方式。你应该有一个事件表和一个联结表返回到你的记录。 – Jamiec

回答

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)[email protected]) 
      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 
+0

你应该至少提供一个链接/提供更多关于拆分功能的信息 – TJB

+0

更新的答案请chek一次 – User

+0

谢谢,但我只需要'索赔'字数。 – Saranya

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 
+1

谢谢,这一个适用于我有的测试数据。几个小时后将会用实时数据进行测试。在我的数据中,如果有多个索赔可用,订单不会改变。 – Saranya

0

我同意其他评论者认为你应该看看你的导入流程和数据架构来存储所有的不同事件作为单独的表行。

但是,如果这是不可能的,你可以做所需的操作相对简单,无需使用cte S或附加功能。当心,这将不超过字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; 

输出:

Event          | Result 
````````````````````````````````````````````|```````````````````````````````````````` 
Payment stopped, Claim, Claim, Claim  | 3 Claims, Payment stopped 
Claim          | 1 Claim 
Claim, Claim, Claim       | 3 Claims, 
Claim, Claim, Payment stopped, Case Closed | 2 Claims, Payment stopped, Case Closed 
Payment stopped, Case Closed    | Payment stopped, Case Closed 
+0

如果项目顺序发生更改,则查询失败。例如:'索赔,付款已停止,索赔,索赔'。我得到的结果为3索赔,,付款停止 – User

+0

@Srinath我没有得到同样的错误...以您的'索赔,支付停止,索赔,索赔'的例子我得到'3索赔,支付的正确结果已停止' – iamdave

+0

我只执行了您的查询,我收到3个索赔,付款已停止。获取额外的逗号 – User

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 @[email protected]+',' 
;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 

而现在只需拨打列标量函数类似下面

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 ║ 
╚════════════════════════════════════════════╩═══════════════════════════════════════╝