2017-10-18 54 views
0

这是一个T-SQL问题,我使用的是Microsoft SQL Server 2014.我加入了三个表格,这非常简单。棘手的部分是这样的:其中一个变量SubtotalKey采用'ABD_1999_MAE_1'的形式。我想将这个变量分成它的四个组成部分,用下划线分隔,并在查询中的特定点处将我的输出中包含四列。我有一个使用标量函数的可行解决方案。它在我们刚才所描述的那种意义上是可行的......但是存在导致它无法使用的性能问题。我已经将标量函数转换为表值函数,并且使用'outer apply'作为解决方案。不幸的是,这会在连接的每个结果行的输出中产生4行。我不知道该从哪里走 - 我想试过枢轴点,但是枢轴点需要数字柱来枢轴转动。所有帮助非常感谢。T-SQL - 如何将变量分成4列进行输出?

下面的代码ufn_SplitString中的表值函数将上面的字符串拆分为1列和4行的表格。 4行分别包含ABD,1999,MAE,1的值。

对于这个问题,SubtotalKey中有4个元素,但实际上,这个数字是可变的。如果我事先不知道需要的额外列的数量是多少,那么解决方案是可能的吗? 这里是我到目前为止的代码:

SELECT 
    t1.t_proj AS time_period, 
    ufn.item, 
    t3.AnnClaimVal AS annuity_outgo_smbel, 
    t3.DeathClaimVal AS death_outgo_smbel, 
    t2.SolvSurvXCF AS annuity_outgo_reins, 
    t2.SolvDeathXCF AS death_outgo_reins, 
    t2.ReinSwapXCF AS mortswap_fixedleg_payment, 
    t3.ExpenseValXCF AS ren_exp, 
    t1.InvExpSCF AS inv_exp, 
    t1.InvExpReinSCF AS inv_exp_reins 

    FROM [sch_ImmAnn].[viw_mdlEV_Formulae] t1 
    INNER JOIN [sch_ImmAnn].[viw_mdl_Formulae] t2 
    ON t1.t_proj = t2.t_proj AND t1._SubtotalKey = t2._SubtotalKey AND t1._Scenario = t2._Scenario AND t1._ExecRun_UID = t2._ExecRun_UID 
    INNER JOIN [sch_ImmAnn].[viw_mdlValue_Formulae] t3 
    ON t1.t_proj = t3.t_proj AND t1._SubtotalKey = t3._SubtotalKey AND t1._Scenario = t3._Scenario AND t1._ExecRun_UID = t3._ExecRun_UID 
    OUTER APPLY sch_Common.ufn_SplitString(t1._SubtotalKey,'_') ufn 
    WHERE t1._ExecRun_UID = @ExecUID AND t1._Scenario = @Scenario 
    AND t1.t_proj >= 0 AND t1.t_proj <= 650 
    ORDER BY SubtotalKey, time_period 

这里是T1一些示例数据:

t_proj SubtotalKey Scenario ExecRun_UID InvExpSCF InvExpReinSCF 
1  ABD_1999_MAE_1  1  36FA21C8 5334.44 37.88 
2  EMM_E12_MAE_3  1  36FA21C8 1894.88 1298.3 
3  XYZ_2008_MAE_1  1  36FA21C8 12.99  10009.33 

这里是T2一些示例数据:

t_proj SubtotalKey Scenario ExecRun_UID SolvSurvXCF SolvDeathXCF ReinSwap  

1  ABD_1999_MAE_1  1  36FA21C8 543.88  12.33   1.2 
2  EMM_E12_MAE_3  1  36FA21C8 2985.11  59.31   4.6 
3  XYZ_2008_MAE_1  1  36FA21C8 309999.12  111.33   9.7 

下面是一些样本数据对于t3:

t_proj SubtotalKey Scenario ExecRun_UID ExpenseValXCF AnnClaimVal DeathClaimVal 
1  ABD_1999_MAE_1  1  36FA21C8 100   901   678 
2  EMM_E12_MAE_3  1  36FA21C8 200   492   121 
3  XYZ_2008_MAE_1  1  36FA21C8 554   510   144 

这里是所期望的输出:

t_proj Col1 Col2 Col3 Col4 Scenario ExecRun_UID InvExpSCF InvExpReinSCF SolvSurvXCF SolvDeathXCF ReinSwap ExpenseValXCF AnnClaimVal DeathClaimVal 
1  ABD 1999 MAE 1  1   36FA21C8  5334.44  37.88   543.88   12.33   1.2  100    901   678 
2  EMM E12 MAE 1  1   36FA21C8  1894.88  1298.3   2985.11  59.31   4.6  200    492   121 
3  XYZ 2008 MAE 1  1   36FA21C8  12.99  10009.33  309999.12  111.33   9.7  554    510   144 

功能代码:

ALTER FUNCTION [sch_Common].[ufn_SplitString] 
(  
     @Input NVARCHAR(MAX), 
     @Character CHAR(1) 
) 

RETURNS @Output TABLE (
     Item NVARCHAR(1000) 
) 

AS 

BEGIN 

     DECLARE @StartIndex INT, @EndIndex INT 

     SET @StartIndex = 1 
     IF SUBSTRING(@Input, LEN(@Input) - 1, LEN(@Input)) <> @Character 
     BEGIN 
      SET @Input = @Input + @Character 
     END 

     WHILE CHARINDEX(@Character, @Input) > 0 
     BEGIN 
      SET @EndIndex = CHARINDEX(@Character, @Input) 
      INSERT INTO @Output(Item) 
      SELECT SUBSTRING(@Input, @StartIndex, @EndIndex - 1) 
      SET @Input = SUBSTRING(@Input, @EndIndex + 1, LEN(@Input)) 
     END 
     RETURN 
END 
+0

你必须做一个动态交叉表或动态支点,因为你没有列固定数量的每本执行时间。 –

+0

这个问题与其他问题不一样,因为我在问是否可以将现有变量拆分为多个变量。另一个问题没有解决这个问题。有一种相似之处,我并不知道会有多少列。 – mediaeval

+0

你表示你正在拆分这些值,并且你的代码中有一个拆分函数。现在你想将这些行成列为正确的?这是我标记为重复的问题中描述的技术。我会重新打开这个,但不确定你的问题是什么。 –

回答

1

假设你如下寻找的东西(Varibale:ABD_1999_MAE_1):

Column1 Column2 Column3 Column4 
ABD  1999 MAE  1 

如果,以上是正确的,那么您可以使用XML方法和CROSS APPLY

SELECT DISTINCT 
     A.t_proj, 
     split.a.value('/X[1]', 'NVARCHAR(MAX)') Col1, 
     split.a.value('/X[2]', 'NVARCHAR(MAX)') Col2, 
     split.a.value('/X[3]', 'NVARCHAR(MAX)') Col3, 
     split.a.value('/X[4]', 'NVARCHAR(MAX)') Col4, 
     A.Scenario, 
     A.ExecRun_UID, 
     A.InvExpSCF, 
     A.InvExpReinSCF, 
     A.SolvSurvXCF, 
     A.SolvDeathXCF, 
     A.ReinSwap, 
     A.ExpenseValXCF, 
     A.AnnClaimVal, 
     A.DeathClaimVal 
FROM 
(
    SELECT T1.t_proj, 
      CAST('<X>'+REPLACE(T1.SubtotalKey, '_', '</X><X>')+'</X>' AS XML) AS String, 
      T1.Scenario, 
      T1.ExecRun_UID, 
      T1.InvExpSCF, 
      T1.InvExpReinSCF, 
      T2.SolvSurvXCF, 
      T2.SolvDeathXCF, 
      T2.ReinSwap, 
      T3.ExpenseValXCF, 
      T3.AnnClaimVal, 
      T3.DeathClaimVal 
    FROM T1 
     INNER JOIN T2 ON T2.t_proj = T1.t_proj 
           AND T2.SubtotalKey = T1.SubtotalKey 
           AND T2.Scenario = T1.Scenario 
     INNER JOIN T3 ON T3.t_proj = T1.t_proj 
           AND T3.SubtotalKey = T3.SubtotalKey 
           AND T3.Scenario = T1.Scenario 
) AS A 
CROSS APPLY String.nodes('/X') split(a); 

所需的结果:

t_proj Col1 Col2 Col3 Col4 Scenario ExecRun_UID InvExpSCF InvExpReinSCF SolvSurvXCF SolvDeathXCF ReinSwap ExpenseValXCF AnnClaimVal DeathClaimVal 
1  ABD 1999 MAE 1  1   36FA21C8  5334.44  37.88   543.88   12.33   1.2  100    901   678 
2  EMM E12 MAE 3  1   36FA21C8  1894.88  1298.3   2985.11  59.31   4.6  200    492   121 
3  XYZ 2008 MAE 1  1   36FA21C8  12.99  10009.33  309999.12  111.33   9.7  554    510   144 
+0

我可以看到这是如何工作的测试值代替。我怎样才能将这个工作写入我现有的代码中? – mediaeval

+0

Yogesh,我添加了原始问题的示例数据。 – mediaeval

+0

非常感谢。这正是我所期待的。最后一个问题......为什么“分裂”在那里?如果我删除它,它仍然可以正常工作。虽然微软的页面上做了同样的事情。再次感谢。 – mediaeval