我有一个带有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。
答案 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 ║
╚════════════════════════════════════════════╩═══════════════════════════════════════╝