2017-01-03 83 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 ║ 
╚════════════════════════════════════════════╩═══════════════════════════════════════╝