2008-12-16 6 views
0

J'ai 3 tables:Cross rejoindre (pivot) avec table n-n contenant des valeurs

TABLE MyColumn (
    ColumnId INT NOT NULL, 
    Label VARCHAR(80) NOT NULL, 
    PRIMARY KEY (ColumnId) 
) 

TABLE MyPeriod (
    PeriodId CHAR(6) NOT NULL, -- format yyyyMM 
    Label VARCHAR(80) NOT NULL, 
    PRIMARY KEY (PeriodId) 
) 

TABLE MyValue (
    ColumnId INT NOT NULL, 
    PeriodId CHAR(6) NOT NULL, 
    Amount DECIMAL(8, 4) NOT NULL, 
    PRIMARY KEY (ColumnId, PeriodId), 
    FOREIGN KEY (ColumnId) REFERENCES MyColumn(ColumnId), 
    FOREIGN KEY (PeriodId) REFERENCES MyPeriod(PeriodId) 
) 

les lignes de maValeur ne sont créées que lorsqu'une valeur réelle est fournie.

Je veux que mes résultats de manière tableau, comme:

Column | Month 1 | Month 2 | Month 4 | Month 5 | 
Potatoes | 25.00 | 5.00 | 1.60 | NULL | 
Apples | 2.00 | 1.50 | NULL | NULL | 

J'ai créé avec succès une croix-join:

SELECT 
    MyColumn.Label AS [Column], 
    MyPeriod.Label AS [Period], 
    ISNULL(MyValue.Amount, 0) AS [Value] 
FROM 
    MyColumn CROSS JOIN 
    MyPeriod LEFT OUTER JOIN 
    MyValue ON (MyValue.ColumnId = MyColumn.ColumnId AND MyValue.PeriodId = MyPeriod.PeriodId) 

Ou, dans LINQ:

from p in MyPeriods 
from c in MyColumns 
join v in MyValues on new { c.ColumnId, p.PeriodId } equals new { v.ColumnId, v.PeriodId } into values 
from nv in values.DefaultIfEmpty() 
select new { 
    Column = c.Label, 
    Period = p.Label, 
    Value = nv.Amount 
} 

Et vu comment créer un pivot dans linq (here ou here):

(en supposant MyDatas est une vue avec le résultat de la requête précédente):

from c in MyDatas 
group c by c.Column into line 
select new 
{ 
    Column = line.Key, 
    Month1 = line.Where(l => l.Period == "Month 1").Sum(l => l.Value), 
    Month2 = line.Where(l => l.Period == "Month 2").Sum(l => l.Value), 
    Month3 = line.Where(l => l.Period == "Month 3").Sum(l => l.Value), 
    Month4 = line.Where(l => l.Period == "Month 4").Sum(l => l.Value) 
} 

Mais je veux trouver un moyen de créer un jeu de résultats avec, si possible, Month1, ... propriétés dynamiques.

Note: Une solution qui se traduit par un n + 1 requête:

from c in MyDatas 
group c by c.Column into line 
select new 
{ 
    Column = line.Key, 
    Months = 
     from l in line 
     group l by l.Period into period 
     select new 
     { 
      Period = period.Key, 
      Amount = period.Sum(l => l.Value) 
     } 
} 

Répondre

0

Avez-vous des périodes de calendrier (1-12) ou les exercices (1-12 ou 1-13 en fonction de l'année) ?

Ne courriez-vous le rapport que pendant un an?

Si possible, je casser l'PeriodId en deux champs de l'année & Période. Cela facilitera la sélection pour une année spécifique. Les requêtes seront plus simples.