2016-01-04 34 views
1

我有下表(#temp1),其中我需要用匹配輸入'VALUE'列替換列'Formula'中的字符串在「Yearmonth」上。如何用基於分組的條件來替換'字符串'

爲了更好的理解,'公式'列可以是任何數學表達式我已經在下面提到了一個簡單的例子。

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實現它。有人可以幫我解決這個問題嗎?

類型1:

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

TYPE2: 使用XML PATH ...在這種情況下,它得到了工作,但我需要更換隻能使用值的字符串,而不是東西基於mathematcal操作字符串。 (因爲公式可能是任何類型的)。

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 

類型3:使用的遞歸...這是隻返回空值...

;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 
+0

這些數字是什麼?(398)','(399)'是什麼意思?有點不清楚 – Devart

+0

它只是字符串和'輸入名稱'列具有相同的字符串名稱...數字表示不同的'ID'爲導入類型... –

+0

表達式**總是**去按照格式'imports(X)[+ imports(Y)...]'?如果是這樣,爲什麼不把X和Y存儲在附加表中?或者你需要支持除'imported'之外的其他源,或者其他操作數,而不僅僅是'+'嗎? –

回答

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選項即可。

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