在 SQL2008 服务器上插入触发器之前,我需要一些帮助来解析值。
我有一个包含文本字段的表(我们称之为源)。字段值可能如下所示
10-15,20-22,25-26,
我想在另一个字段中用逗号分隔值(比如说目标):
10,11,12,13,14,15,20,21,22,25,26,
这可以在插入触发器之前完成还是我需要某种外部应用程序?
谢谢你。
在 SQL2008 服务器上插入触发器之前,我需要一些帮助来解析值。
我有一个包含文本字段的表(我们称之为源)。字段值可能如下所示
10-15,20-22,25-26,
我想在另一个字段中用逗号分隔值(比如说目标):
10,11,12,13,14,15,20,21,22,25,26,
这可以在插入触发器之前完成还是我需要某种外部应用程序?
谢谢你。
首先,您需要创建一个Table Valued function
which takestart
和end
value 来生成sequence
.This 使用完成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) = '')
)
上面的解决方案发布在这里,它基本上使用 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
createcolumns
来存储range
of 类型int
更新
只是为了在同一页上。Insert Trigger
您在包含类似值的源表上创建10-15,20-22,25-26
。您需要将这些值转换为sequence
并将其插入到Target
表中。如果是这种情况,您可以使用下面的代码。
基本上创建的触发器从触发器中的逻辑表中Derived Table
插入数据。然后使用上面的方法,你在表中插入inserted
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
我建议这些数字应该真正存储在一个单独的表中,例如 Range (start int, end int),其中包含指向您引用的表的 many-1 链接,这应该使这样的查询更简单,并为您节省其他潜在的麻烦,但也许你有充分的理由这样做。在这种情况下,我建议创建一个 UDF 来生成 CSV 字符串并将该字段声明为引用 UDF 的计算列。如果这是一个频繁使用或经常更新的表,请注意潜在的性能问题。