如何更换' Strings'具有基于group by子句的数值

时间:2016-01-04 08:16:35

标签: sql sql-server sql-server-2012

我有下表(#temp1),我需要替换列中的字符串' Formula'使用匹配的输入' VALUE'基于小组'年纪'。

的专栏

'公式'列可以是任何数学表达式以便更好地理解我在下面提到了一个简单的例子。

  IDNUM  formula                      INPUTNAME      VALUE    YEARMONTH
---------------------------------------------------------------------
  1      imports(398)+imports(399)    imports(398)    17.000  2003:1
  2      imports(398)+imports(399)    imports(398)    56.000  2003:2
  3      imports(398)+imports(399)    imports(399)    15.000  2003:1
  4      imports(398)+imports(399)    imports(399)    126.000 2003:2

例如:从上表中我需要输出为

Idnum  Formula        Yearmonth
 1.    17.00 +15.00    2003:1
 2.    56.00 +126.00   2003:2

我尝试了以下不同的查询来自各种建议,但是coludnt实现了它。有人可以帮帮我这个吗?

Type1:

SELECT
REPLACE(FORMULA, INPUTName, AttributeValue) AS realvalues, 
yearmonth 
FROM #temp1
GROUP BY yearmonth

TYPE2: 使用XML PATH ...在这种情况下它已经工作但我只需要用值替换字符串而不是根据数学运算填充字符串。(因为公式可能是任何类型)。

SELECT
IDNUM = MIN(IDNUM),
FORMULA = 
    (SELECT STUFF(
        (SELECT ' +' + CONVERT(VARCHAR(10), Value)
        FROM #temp1
        WHERE YEARMONTH = t1.YEARMONTH
        FOR XML PATH(''))
    ,1, 2, '')),
YEARMONTH
FROM #TEMP1 t1
GROUP BY YEARMONTH

TYPE3:使用递归...这只返回空值......

;with t as (
  select t.*,
         row_number() over (partition by yearmonth order by idnum) as seqnum,
         count(*) over (partition by yearmonth) as cnt
  from #temp1 t


 )

 ,cte as (
  select t.seqnum, t.yearmonth, t.cnt,
         replace(formula, inputname, AttributeValue) as formula1
  from t
  where seqnum = 1
  union all
  select cte.seqnum, cte.yearmonth, cte.cnt,
         replace(CTE.formula1, T.inputname, T.AttributeValue) as formula2
  from cte join
       t
       on cte.yearmonth = t.yearmonth 

       AND  cte.seqnum = t.seqnum + 1 
)
   select row_number() over (order by (select null)) as id,formula1
   from cte
   where seqnum = cnt

2 个答案:

答案 0 :(得分:2)

这是使用递归CTE的完整工作示例:

DECLARE @DataSource TABLE
(
    [IDNUM] TINYINT
   ,[formula] VARCHAR(MAX)
   ,[INPUTNAME] VARCHAR(128)
   ,[VALUE] DECIMAL(9,3)
   ,[YEARMONTH] VARCHAR(8)
);

INSERT INTO @DataSource ([IDNUM], [formula], [INPUTNAME], [VALUE], [YEARMONTH])
VALUES ('1', 'imports(398)+imports(399)', 'imports(398)', '17.000', '2003:1')
      ,('2', 'imports(398)+imports(399)', 'imports(398)', '56.000', '2003:2')
      ,('3', 'imports(398)+imports(399)', 'imports(399)', '15.000', '2003:1')
      ,('4', 'imports(398)+imports(399)', 'imports(399)', '126.000', '2003:2')
      ,('5', '(imports(391)+imports(392)-imports(393))/imports(394)', 'imports(391)', '5.000', '2003:3')
      ,('6', '(imports(391)+imports(392)-imports(393))/imports(394)', 'imports(392)', '10.000', '2003:3')
      ,('7', '(imports(391)+imports(392)-imports(393))/imports(394)', 'imports(393)', '3.000', '2003:3')
      ,('8', '(imports(391)+imports(392)-imports(393))/imports(394)', 'imports(394)', '-5.000', '2003:3');

WITH DataSource AS
( 
    SELECT ROW_NUMBER() OVER(PARTITION BY [YEARMONTH] ORDER BY [IDNUM]) AS [ReplacementOrderID]
          ,[YEARMONTH]
          ,[formula]
          ,[INPUTNAME] AS [ReplacementString]
          ,[VALUE] AS [ReplacementValue]
    FROM @DataSource
),
RecursiveDataSource AS
(
    SELECT [ReplacementOrderID]
          ,[YEARMONTH]
          ,REPLACE([formula], [ReplacementString], [ReplacementValue]) AS [formula]
    FROM DataSource
    WHERE [ReplacementOrderID] = 1
    UNION ALL
    SELECT DS.[ReplacementOrderID]
          ,DS.[YEARMONTH]
          ,REPLACE(RDS.[formula], DS.[ReplacementString], DS.[ReplacementValue]) AS [formula]
    FROM RecursiveDataSource RDS
    INNER JOIN DataSource DS
        ON RDS.[ReplacementOrderID] + 1 = DS.[ReplacementOrderID]
        AND RDS.[YEARMONTH] = DS.[YEARMONTH]
)
SELECT RDS.[YEARMONTH]
      ,RDS.[formula]
FROM RecursiveDataSource RDS
INNER JOIN 
(
    SELECT [YEARMONTH]
          ,MAX([ReplacementOrderID]) AS [ReplacementOrderID]
    FROM DataSource
    GROUP BY [YEARMONTH]
) DS
    ON RDS.[YEARMONTH] = DS.[YEARMONTH]
    AND RDS.[ReplacementOrderID] = DS.[ReplacementOrderID]
ORDER BY RDS.[YEARMONTH]

enter image description here

通常,您只想在一个语句中对字符串执行多次替换。您可以使用MAXRECURSION选项获得许多替换值。

答案 1 :(得分:0)

--Create sample data
DROP TABLE #temp1
CREATE TABLE #temp1 (IDNUM int, formula varchar(max), INPUTNAME varchar(max), VALUE decimal, YEARMONTH varchar(max))
INSERT INTO #temp1 VALUES 
    (1, 'imports(398)+imports(399)', 'imports(398)', 17.000, '2003:1'),
    (2, 'imports(398)+imports(399)', 'imports(398)', 56.000, '2003:2'),
    (3, 'imports(398)+imports(399)', 'imports(399)', 15.000, '2003:1'),
    (4, 'imports(398)+imports(399)', 'imports(399)', 126.000, '2003:2')

--Query
;WITH t as (
    SELECT formula, YEARMONTH, IDNUM
    FROM #temp1
UNION ALL
    SELECT REPLACE(a.formula, b.INPUTNAME, CAST(b.VALUE AS varchar(100))) AS formula, a.YEARMONTH, a.IDNUM
    FROM t a
    JOIN #temp1 b ON a.YEARMONTH = b.YEARMONTH AND a.formula LIKE '%' + b.INPUTNAME + '%'
)
SELECT MIN(IDNUM) AS IDNUM, formula, YEARMONTH
FROM t
WHERE formula not LIKE '%imports(%'
GROUP BY formula, YEARMONTH