3

在 SQL2008 服务器上插入触发器之前,我需要一些帮助来解析值。

我有一个包含文本字段的表(我们称之为源)。字段值可能如下所示

10-15,20-22,25-26,

我想在另一个字段中用逗号分隔值(比如说目标):

10,11,12,13,14,15,20,21,22,25,26,

这可以在插入触发器之前完成还是我需要某种外部应用程序?

谢谢你。

4

2 回答 2

1

首先,您需要创建一个Table Valued functionwhich takestartendvalue 来生成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 columnrowsfunction

 ;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将范围设置为StartValueEndValue

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不是将其存储为stringcreatecolumns来存储rangeof 类型int

更新

只是为了在同一页上。Insert Trigger您在包含类似值的源表上创建10-15,20-22,25-26。您需要将这些值转换为sequence并将其插入到Target表中。如果是这种情况,您可以使用下面的代码。

基本上创建的触发器从触发器中的逻辑表中Derived Table插入数据。然后使用上面的方法,你在表中插入insertednested CTE'ssequencetarget

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
于 2013-03-25T13:35:05.123 回答
0

我建议这些数字应该真正存储在一个单独的表中,例如 Range (start int, end int),其中包含指向您引用的表的 many-1 链接,这应该使这样的查询更简单,并为您节省其他潜在的麻烦,但也许你有充分的理由这样做。在这种情况下,我建议创建一个 UDF 来生成 CSV 字符串并将该字段声明为引用 UDF 的计算列。如果这是一个频繁使用或经常更新的表,请注意潜在的性能问题。

于 2013-03-25T12:50:12.887 回答