2017-03-02 1 views
2

J'ai du mal à réunir les lignes d'hier pour extraire des données historiques. Je supprime une grande partie de mon code pour plus de lisibilité, et j'utilise simplement "SELECT *" en lieu et place - c'est un gros.SP ou Fonction sur des données Univo en utilisant des noms de colonnes

Voici une version dénudée du UNPIVOT:

SELECT * 
FROM EODMarkHistory 
    UNPIVOT 
    (
    Value 
    FOR Name IN (C0,C1,C2,C3,C4,C5,C6,C7,C8,C9,C10,C11,C12 
       ,P0,PLow,PHigh,P1,P2,P3,P4,P5,P6,P7,P8,P9,P10,P11,P12 
       ,F0,F1,F2,F3,F4,F5,F6,F7,F8,F9,F10,F11,F12,F13,F14,F15,F16,F17,F18,F19,F20,F21,F22,F23,F24 
       ,Q1,Q2,Q3,Q4,Q5,Q6,Q7,Q8) 
    ) piv 
    INNER JOIN ... 

Toutes ces colonnes contiennent des valeurs « marquer », et je dois saisir les « marques » d'hier à comparer. J'essaie de ne pas avoir à lister chacun d'entre eux dans une instruction IF ou CASE dans une fonction. J'ai écrit une procédure stockée qui fonctionne avec SQL dynamique:

SET @MarkDate = DATEADD(DAY,-1,@MarkDate) 
DECLARE @DynamicSQL nvarchar(800) = N'SELECT ' + @Column + ' FROM EODMarkHistory WHERE SubGroupCode=''' + @ProductCode + ''' AND MarkDate = ''' + CONVERT(varchar(10),@MarkDate,121) + '''' 

exec sp_executesql @DynamicSQL 

Mais bien sûr SQL dynamique ne peut pas entrer dans une fonction, c'est un SP, je ne peux pas appeler cette ligne.

Est-ce que j'ai d'autres options que d'énumérer toutes les colonnes possibles dans une fonction? Si nous ajoutons des colonnes dans le futur, la maintenance devient un problème.

Je suis à la recherche d'un moyen intégré et non-hacky pour y parvenir. Si je doit le faire avec un codage dur dans une fonction (ou un curseur) je le ferai. J'espérais juste que quelqu'un connaisse un moyen plus rapide d'obtenir SQL dynamique (ou une autre option avec le même résultat) pour travailler dans ce cas? De préférence en ligne. Si la dynamique en ligne n'est pas possible, je peux le coder sans assistance.

EDIT - petit exemple de travail

Exemple de code seulement - Ceci est loin d'être correct ...

DECLARE @Test TABLE(MarkDate varchar(10),C1 int, C2 int, C3 int, C4 int) 
DECLARE @MarkDate datetime = '3/2/2017' 
INSERT INTO @Test 
VALUES 
('3/2/2017',50,-50,100,-100) 
,('3/1/2017',75,-75,125,-125) 

SELECT * FROM @Test 

--Current result 
SELECT * 
FROM @Test 
    UNPIVOT 
    (
     VALUE 
     FOR Name IN (C1,C2,C3,C4) 
    ) piv 

--Wanted Result 
SELECT '3/2/2017' AS MarkDate, 50 AS Value, 'C1' AS Name, 75 AS YestValue 
UNION 
SELECT '3/2/2017' AS MarkDate, -50 AS Value, 'C2' AS Name, -75 AS YestValue 
UNION 
SELECT '3/2/2017' AS MarkDate, 100 AS Value, 'C3' AS Name, 125 AS YestValue 
UNION 
SELECT '3/2/2017' AS MarkDate, -100 AS Value, 'C4' AS Name, -125 AS YestValue 
+0

Peut-être un petit échantillon de données et les résultats souhaités seraient utiles. Il existe plusieurs techniques qui ne nécessitent pas de XML dynamique (pas besoin de tous les champs de l'exemple) –

Répondre

2

Cette approche utilise un TVF pour créer une structure EAV (Entité Attribut Valeur) de pratiquement n'importe quelle table, enregistrement ou jeu de données. Peut s'appliquer être appliqué dans une APPLICATION CROISEE aussi bien. Voir les commentaires au bas de l'UDF.

Maintenant, si vous ne voulez pas UDF, cette approche peut facilement être utilisé dans une CROSS APPLIQUER

Exemple

-- Create Some Sample Data 
Declare @Test Table (MarkDate varchar(10),C1 int, C2 int, C3 int, C4 int) 
Insert Into @Test Values ('3/2/2017',50,-50,100,-100),('3/1/2017',75,-75,125,-125) 

-- Set Key Dates 
Declare @Date1 date = '2017-03-01' 
Declare @Date2 date = '2017-03-02' 

-- Execute Code 
Select MarkDate = @Date2 
     ,Value  = max(case when [email protected] then Value end) 
     ,Name  = Attribute 
     ,YestValue = max(case when [email protected] then Value end) 
From [dbo].[udf-EAV]((Select * from @Test Where MarkDate in (@Date1,@Date2) for XML RAW)) 
Group By Attribute 

Retours

MarkDate Value Name  YestValue 
2017-03-02 50  C1   75 
2017-03-02 -50  C2   -75 
2017-03-02 100  C3   125 
2017-03-02 -100 C4   -125 

L'UDF si intéressé

CREATE FUNCTION [dbo].[udf-EAV](@XML xml) 
Returns Table 
As 
Return (
    with cteKey(k) as (Select Top 1 xAtt.value('local-name(.)','varchar(100)') From @XML.nodes('/row') As A(xRow) Cross Apply A.xRow.nodes('./@*') As B(xAtt))  

    Select Entity = xRow.value('@*[1]','varchar(50)') 
      ,Attribute = xAtt.value('local-name(.)','varchar(100)') 
      ,Value  = xAtt.value('.','varchar(max)') 
    From @XML.nodes('/row') As A(xRow) 
    Cross Apply A.xRow.nodes('./@*') As B(xAtt) 
    Where xAtt.value('local-name(.)','varchar(100)') Not In (Select k From cteKey) 
) 
-- Notes: First Field in Query will be the Entity 
-- Select * From [dbo].[udf-EAV]((Select UTCDate=GetUTCDate(),* From sys.dm_os_sys_info for XML RAW)) 
+0

L'assistant! Tyvm, j'aurais littéralement passé des années là-dessus avant d'arriver ici. – Aaron