我需要一些帮助在SQL2008服务器上插入触发器之前解析值。
我有一个包含文本字段的表(让我们称之为源代码)。 字段值可能如下所示
10-15,20-22,25-26,
我希望在另一个字段中使用逗号分隔值(比如说目标):
10,11,12,13,14,15,20,21,22,25,26,
这可以在插入触发器之前完成,还是需要某种外部应用程序?
谢谢。
答案 0 :(得分:1)
首先,您需要创建Table Valued function
,其start
和end
值生成sequence
。这是使用recursive cte
CREATE FUNCTION FnGetRange(@startValue int,@endValue int)
RETURNS @rtnTable TABLE
(
generatedVal VARCHAR(MAX)
)
AS
BEGIN
;with cte(startValue,rangeVal,generatedVal)
as
(
Select @startValue,@endValue,@startValue as generatedVal
union all
Select startValue, rangeVal, generatedVal+1
from cte r
where rangeVal > generatedVal
)
Insert into @rtnTable
Select generatedVal from cte
return
END
您需要split
将single column
导入rows
,以便获取范围并将其传递给function
;with cte(range) as
(
SELECT
RIGHT(LEFT(T.rangeVal,Number-1),
CHARINDEX(',',REVERSE(LEFT(','+T.rangeVal,Number-1)))) as range
FROM
master..spt_values,
yourTable T
WHERE
Type = 'P' AND Number BETWEEN 1 AND LEN(T.rangeVal)+1
AND
(SUBSTRING(T.rangeVal,Number,1) = ',' OR SUBSTRING(T.rangeVal,Number,1) = '')
)
以上解决方案已发布here,它基本上使用master..spt_values来生成序列
cte将返回结果
range
10-15
20-22
25-26
现在您需要split
范围StartValue
和EndValue
rangeCte (startValue,endValue) as
(
Select parsename(replace(range,'-','.'),2) as startValue,
parsename(replace(range,'-','.'),1) as endValue
from cte
)
以上rangeCTE
将返回
startValue endValue
10 15
20 22
25 26
获得这些值后,您只需使用FnGetRange
cross apply
RowValue (rangeSep) as
( Select val.generatedVal as rangeSep from rangeCte r
CROSS APPLY
dbo.FnGetRange(r.StartValue,r.endValue) AS val
)
这将生成序列但它将分为多行。要将其转换为单row
,请使用xml path
SELECT STUFF(
(SELECT ',' + rangeSep
FROM RowValue
FOR XML PATH(''),type).value('.','varchar(max)'),1,1,'')
现在将最终查询的所有CTE's
组合在一起
;with cte(range) as
(
SELECT
RIGHT(LEFT(T.rangeVal,Number-1),
CHARINDEX(',',REVERSE(LEFT(','+T.rangeVal,Number-1)))) as range
FROM
master..spt_values,
yourTable T
WHERE
Type = 'P' AND Number BETWEEN 1 AND LEN(T.rangeVal)+1
AND
(SUBSTRING(T.rangeVal,Number,1) = ',' OR SUBSTRING(T.rangeVal,Number,1) = '')
),rangeCte (startValue,endValue) as
(
Select parsename(replace(range,'-','.'),2) as startValue,
parsename(replace(range,'-','.'),1) as endValue
from cte
),RowValue (rangeSep) as
( Select val.generatedVal as rangeSep from rangeCte r
CROSS APPLY
dbo.FnGetRange(r.StartValue,r.endValue) AS val
)
SELECT STUFF(
(SELECT ',' + rangeSep
FROM RowValue
FOR XML PATH(''),type).value('.','varchar(max)'),1,1,'')
结果将是
10,11,12,13,14,15,20,21,22,25,26
正如其他人所建议的那样,您应该认真更改table design
。而不是将其存储为string
创建columns
来存储range
类型int
}
更新了
只是在同一页面上。您在源表上创建Insert Trigger
,其中包含10-15,20-22,25-26
之类的值。您需要将这些值转换为sequence
并将其插入Target
表。如果是这种情况,则可以使用以下代码。
基本上创建的触发器Derived Table
插入inserted
中trigger中逻辑表的数据。然后使用上面的nested CTE's
插入sequence
在target
表
create trigger tri_inserts on a
after insert
as
set nocount on
Declare @RangeTable table
(rangeVal varchar(max))
Insert into @RangeTable
Select rangeColumn from INSERTED
;with cte(range) as
(
SELECT
RIGHT(LEFT(T.rangeVal,Number-1),
CHARINDEX(',',REVERSE(LEFT(','+T.rangeVal,Number-1)))) as range
FROM
master..spt_values,
@RangeTable T
WHERE
Type = 'P' AND Number BETWEEN 1 AND LEN(T.rangeVal)+1
AND
(SUBSTRING(T.rangeVal,Number,1) = ',' OR SUBSTRING(T.rangeVal,Number,1) = '')
),rangeCte (startValue,endValue) as
(
Select parsename(replace(range,'-','.'),2) as startValue,
parsename(replace(range,'-','.'),1) as endValue
from cte
),RowValue (rangeSep) as
( Select val.generatedVal as rangeSep from rangeCte r
CROSS APPLY
dbo.FnGetRange(r.StartValue,r.endValue) AS val
)
Insert into Target(DestColumn) --Change the target name
SELECT STUFF(
(SELECT ',' + rangeSep
FROM RowValue
FOR XML PATH(''),type).value('.','varchar(max)'),1,1,'')
GO
答案 1 :(得分:0)
我建议这些数字应该存储在一个单独的表中,例如范围(start int,end int)与你引用的表的多个-1链接应该使这样的查询更加简单并且为你节省其他潜在的麻烦,但也许你有充分的理由这样做。在这种情况下,我建议创建一个UDF来生成CSV字符串,并将该字段声明为引用UDF的计算列。如果这是一个频繁使用或经常更新的表,请注意潜在的性能问题。