2009-03-25 8 views
0

Je dois calculer le carnet de commandes d'une table: composants (ProductId, ComponentId, état, StatusDate) où ComponentId, le statut et StatusDate sont la clé primaire. ProductId est une clé étrangère. Exemple:

prod1, comp1, 01, 05/01/2009
prod1, comp1, 02, 05/01/2009
prod1, comp1, 03, 06/01/2009
prod1, comp1, 01, 07/01/2009
prod1, comp1, 02, 20/01/2009
prod2, comp2, 01, 22/01/2009
prod1, comp1, 02, 23/01/2009
prod1, comp1, 03, 31/01/2009

Fondamentalement ce que j'essaie de calculer est le nombre de composants par semaine dans le statut inférieur à 03. L'utilisateur final introduira une date d'intervalle ainsi je dois montrer toutes les semaines dans l'intervalle même s'il y a pas d'arriéré pour une semaine. Résultat attendu lorsque l'utilisateur final introduit 01/01/2009-22/01/2009:

Week, Backlog
1,NULL/0
2,1
3,1
4,2

Explication de la Semaine 2: COMP1 état de portée 03 dans la semaine, mais puis retourne à l'état 01
Toute aide est plus bienvenue, mercicalcul du carnet de commandes SQL (MS Access)

+0

Vous pourriez vouloir expliquer votre problème un peu plus. Par exemple, est une semaine Sun-Sat ou tout simplement les 7 premiers jours à partir de la date de début dans votre intervalle? –

Répondre

0

Ceci est une réponse partielle en ce sens que je ne vois pas d'où vient la semaine 3 (11-18 janvier 2009) dans votre exemple. Il illustre l'utilisation d'une table de compteur pour obtenir une ligne pour les valeurs manquantes.

SELECT Counter,WeekNo, CountofStatus FROM Counter LEFT JOIN 
    (SELECT Format([StatusDate],"ww") AS WeekNo, COUNT(c.Status) AS CountOfStatus 
    FROM components c 
    WHERE c.StatusDate BETWEEN #1/1/2009# AND #1/22/2009# 
    AND c.Status<3 
    GROUP BY Format([StatusDate],"ww")) Comp 
ON Val(Comp.Weekno)=Counter.Counter 
WHERE Counter.Counter>=Val(Format(#1/1/2009#,"ww")) 
AND Counter.Counter<=Val(Format(#1/22/2009#,"ww")) 
+0

Merci beaucoup Remou, je vais essayer tout de suite. Dans l'exemple, la semaine 3 a un composant dans l'état inférieur à 03 (comp1 est dans l'état 01 à partir de la semaine 2) –

+0

Donc le statut est continu et seulement marqué à la date changée? Si oui, mon exemple ne convient pas. – Fionnuala

+0

Correct, j'ai essayé avec un UDF: pour chaque semaine vérifier par chaque composant ce statut de statusDate maximum. Si le statut est <3, je compte. Si ce n'est pas le composant trouvé pour la semaine donnée, je vérifie l'état du dernier composant Statusdate avant la semaine donnée. Mais cela prend des âges et le dossier d'accès se développe comme l'enfer :( –

1

Je devine un peu à ce que vous essayez de faire, mais voici ma meilleure estimation:

D'abord, vous devriez avoir une table de calendrier dans votre base de données:

CREATE TABLE Calendar (
    calendar_date DATETIME NOT NULL, 
    week_number INT NOT NULL, 
    CONSTRAINT PK_Calendar PRIMARY KEY CLUSTERED (calendar_date) 
) 
GO 

INSERT INTO Calendar (calendar_date, week_number) VALUES ('1/1/2009', 1) 
INSERT INTO Calendar (calendar_date, week_number) VALUES ('2/1/2009', 2) 
etc. 

Vous pouvez ajouter des colonnes supplémentaires à la table en fonction de vos besoins professionnels. Par exemple, une colonne de bit "is_holiday" pour savoir si votre bureau est fermé ce jour-là. Cette table rend tellement de requêtes différentes triviales.

Maintenant, pour votre problème:

SELECT 
    CAL.week_number, 
    COUNT(DISTINCT C.component_id) 
FROM 
    Calendar CAL 
LEFT OUTER JOIN Components C ON 
    C.status_date = CAL.calendar_date AND 
    C.status IN ('01', '02') 
WHERE 
    CAL.calendar_date BETWEEN @start_date AND @end_date 
GROUP BY 
    CAL.week_number 

J'ai utilisé le IN pour le statut puisque vous utilisez des chaînes, donc « < « 03 » » pourrait ne pas toujours vous donner ce que vous voulez. Est-ce que '1' est moins que '03' dans votre esprit?

En outre, s'il existe un composant temporel sur l'une de vos dates, les vérifications d'égalité et BETWEEN doivent être modifiées.

EDIT: Je viens de voir les commentaires sur l'autre réponse. Si vous faites affaire avec seulement des changements d'état, la requête suivante devrait fonctionner, bien qu'il puisse y avoir une méthode plus performante:

SELECT 
    CAL.week_number, 
    COUNT(DISTINCT C.component_id) 
FROM 
    Calendar CAL 
LEFT OUTER JOIN Components C ON 
    C.status_date <= CAL.calendar_date AND 
    C.status IN ('01', '02') 
LEFT OUTER JOIN Components C2 ON 
    C2.component_id = C.component_id AND 
    C2.status_date > C.status_date AND 
    C2.status_date <= CAL.calendar_date 
WHERE 
    CAL.calendar_date BETWEEN @start_date AND @end_date AND 
    C2.component_id IS NULL 
GROUP BY 
    CAL.week_number 

Je ne sais pas où le produit s'inscrit dans tout cela cependant.