2017-10-18 28 views
0

Ceci est une question T-SQL, j'utilise Microsoft SQL Server 2014. Je joins trois tables, ce qui est très simple. La partie délicate est la suivante: l'une des variables, SubtotalKey, prend la forme 'ABD_1999_MAE_1'. Je voudrais diviser cette variable en ses quatre composants, délimités par le trait de soulignement, et inclure les quatre colonnes dans ma sortie à un point spécifique dans la requête. J'ai une solution réalisable qui utilise une fonction scalaire. Praticable dans le sens où il fait ce que je viens de décrire ... mais il y a des problèmes de performance qui le rendent inutilisable. Depuis, j'ai converti la fonction scalaire en une fonction table et j'utilise 'outer apply' comme solution. Malheureusement, cela se traduit par 4 lignes dans la sortie par résultat ligne de la jointure. Je ne sais pas où aller à partir d'ici - j'ai essayé le pivot, mais le pivot a besoin de colonnes numériques pour pivoter, je pense. Tous aident beaucoup apprécié.T-SQL - Comment diviser une variable en 4 colonnes pour la sortie?

La fonction de valeur de table dans le code ci-dessous, ufn_SplitString, divisera la chaîne ci-dessus en une table avec 1 colonne et 4 lignes. Les 4 lignes contiennent les valeurs, respectivement, ABD, 1999, MAE, 1.

Pour les besoins de cette question, il y a 4 éléments dans SubtotalKey, mais en réalité, le nombre sera variable. Une solution est-elle possible, si je ne sais pas à l'avance quel sera le nombre de colonnes supplémentaires requises? Voici mon code à ce jour:

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 

Voici quelques exemples de données pour 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 

Voici quelques exemples de données pour 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 

Voici quelques exemples de données pour 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 

Voici la sortie désirée:

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 

Code de fonction:

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

Vous devez faire une croix onglet dynamique ou dynamique, car pivot vous ne disposez pas d'un nombre fixe de colonnes à chaque fois que cette exécution. –

+0

Cette question n'est pas la même que l'autre, car je demande s'il est possible de diviser une variable existante en plusieurs variables. L'autre question ne traite pas de cela. Il y a une similitude dans le fait que je ne sais pas finalement combien de colonnes il y aura. – mediaeval

+0

Vous avez déclaré que vous divisez ces valeurs et que votre code comporte une fonction de division. Maintenant, vous voulez faire ces lignes en colonnes à droite? C'est la technique décrite dans la question que j'ai marquée comme doublon. Je vais rouvrir cela mais je ne suis pas vraiment sûr de votre question. –

Répondre

1

En supposant que vous cherchez quelque chose comme ci-dessous (varibale: ABD_1999_MAE_1):

Column1 Column2 Column3 Column4 
ABD  1999 MAE  1 

Si, au-dessus est correcte, Vous pouvez utiliser la méthode XML et 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); 

Résultat souhaité:

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

Je peux voir comment cela fonctionne pour une valeur de test à la place de . Comment puis-je travailler cela dans mon code existant? – mediaeval

+0

Yogesh, j'ai ajouté des données d'échantillon à la question originale. – mediaeval

+0

merci beaucoup. Ceci est exactement ce que je cherchais. Une dernière question ... pourquoi la "scission" est-elle là? Si je l'enlève, ça fonctionne toujours bien. Bien que la page Microsoft sur ce fait la même chose. Merci encore. – mediaeval