0
votes

Comment retourner des enregistrements parent, uniquement s'il y a un enregistrement enfant, avec une date maximale qui tombe entre une plage de date?

Je dois retourner tous les éléments de parents terminés de la table de mes parents, lorsqu'ils sont terminés dans une plage de dates. Toutes les actions contre un parent sont stockées dans une table enfant, parent_actions.Le Difficulté que je dois avoir, c'est qu'il peut y avoir plus d'actions après l'action terminée, voire plusieurs actions terminées stockées pour ce parent_id et je n'ai besoin que de la déclaration du parent de la MAX Action est une action complétée et elle relève une plage de dates sélectionnée par l'utilisateur.

J'ai essayé de chercher sur les forums, mais la plupart de ce que j'ai trouvé a été "Comment trouver la date maximale d'un enregistrement d'enfant pour un dossier de parent", qui a été utile dans comment faire max, mais pas utile à mon problème exact. P>

Je ne vous souviens pas tout ce que j'ai essayé, mais j'essaie actuellement ce code, qui renvoie les résultats corrects (11 lignes), il faut juste 10 minutes en raison de la terriblement inefficace. SQL. P>

Sample data:
STATUS
ID, DESC
1, ENTERED
2, SUBMITTED
99, COMPLETED

ACTIONS
ID, DESC
1, ENTER
2, SUBMIT
99, COMPLETE

PARENT
ID, STATUS
1, 99
2, 1
3, 99
4, 99

PARENT_ACTIONS
ID, PARENT_ID, ACTION_ID, ACTION_DATE
1, 1, 1, 04/01/2019
2, 1, 2, 04/05/2019
3, 1, 99, 04/11/2019
4, 2, 1, 04/11/2019
5, 3, 1, 04/15/2019
6, 3, 2, 04/16/2019
7, 3, 99, 04/17/2019
8, 3, 2, 04/18/2019 --Parent sent back to submitted status
9, 4, 1, 04/01/2019
10, 4, 2, 04/11/2019
11, 4, 99, 04/15/2019
12, 4, 99, 04/24/2019 --Completion details updated by customer, business rules require a new complete action be written


1 commentaires

Pouvez-vous fournir des schémas de table, des échantillons de données et une sortie attendue? De plus, quel SGBD utilisez-vous (MSSQL, MySQL, etc.)?


3 Réponses :


0
votes

édité: Commandez les actions par date dans une ordonnance descendante, puis prenant la première action (dernière) action. Le statut de cette action doit être 99 et la date de sa date doit être dans la plage requise: xxx

modifier (selon le lien suivant, ce code devrait être équivalent aux fonctions de classement de T-SQL qui devrait être Plus efficace: https://smehrozalam.wordpress.com/2009/12/29/linq-how-a-get-the-latest-last-record-with-group-by-clause/ ) xxx


6 commentaires

Merci pour la réponse; Cependant, ce n'est pas ce que je demande. Je dois retourner un parent si la date d'action maximale est destinée à une action terminée et que la date d'action maximale est comprise entre la plage de dates. Je vais modifier ma question avec des exemples de données, vous pour préciser.


Cela ne renvoie pas les résultats souhaités. Je reçois 153 articles, quand je devrais avoir 9. En regardant dans les 144 articles supplémentaires, je constate que ce sont des enregistrements anciens avec de mauvaises données - ils n'ont aucune action dans la table des actions, mais elles sont encore incluses avec cette code. Cette requête prend également plus de 10 minutes à compléter. Il semble que le code que j'ai dans ma question peut être le code correct, il ne s'agit que d'exécuter extrêmement mal, et je ne pourrai pas comprendre pourquoi.


Il semble que nos deux codes souffrent du "Select n + 1 problème". J'ai trouvé un message qui peut fournir une meilleure solution, voir ma réponse modifiée.


Cela semble bien fonctionner pour un petit ensemble de données, mais si les paramètres de date sont élargis, je me retrouve avec un hashset avec des éléments de 25 km, cela ne se traduit pas très bien sur une clause SQL où l'utilisation de parendids.Contains () . Je ne pense pas que cela souffre du problème "Select n + 1, car il génère une seule requête qui renvoie toutes les informations dont j'ai besoin. Il apparaît que mon problème est que le SQL généré a beaucoup de casse Numéro (10,0) à la place des colonnes de base de données entier. Si je retire le coulé à partir du SQL, il fonctionne aussi bien que mon SQL écrit.


Êtes-vous sûr que cela ne fonctionne pas plus vite car il s'agit d'une deuxième course et que le cache de la DB entre en action? C'est un peu étrange comment il peut trouver le max pour chaque parent de manière efficace sans utiliser de groupement. Pouvez-vous poster le SQL généré?


Je viens de modifier le fichier .edmx dans le bloc-notes pour modifier le type de mappage de colonne en "INT" du "numéro". Une fois que j'ai fait cela, le SQL généré n'a plus toutes les fonctions de distribution et s'exécute rapidement. Il est frustrant que, avec la base de données de base de données, je ne peux pas modifier les mappages de la colonne dans l'interface utilisateur et qu'elle mappait une colonne Oracle Entier à un type de numéro.



0
votes

J'ai seulement besoin que le parent est retourné si l'action Max est une action terminée et se situe dans une plage de date sélectionnée par l'utilisateur. P>

Vous voulez donc que le parent, si le statut du parent terminé (99) et la dernière parentalité de ce parent était terminé avec une date entre BEGINDEATE et ENDDATE. Ou plus précis: la dernière parentalaction de ce parent a une action actionidée (99) et une action d'action entre commencé et enddate. P>

chaque fois que vous voulez un "article avec ses sous-éléments", comme une "école avec Ses étudiants ", un" client avec ses commandes ", un" produit avec ses producteurs ", envisagent d'utiliser QUERYABLE.GROUPBY P>

var parentsThatCompletedTheirActionsInTime = dbContext.Parents
    .Where(parent => parent.Status == 99) // = completed
    .GroupJoin(dbContext.ParentActions,   // GroupJoin with the ParentActions
        parent => parent.Id,              // from every Parent take the primary key
    parentAction => parentAction.Id,      // from every ParentAction the foreign key

    // ResultSelector: take the parent and all its matching parentActions
    // to make one new object
    (parent, actionsOfThisParent) => new
    {
        Parent = parent,
        LastParentAction = actionsOfThisParent
           .Select(action => new
           {
               IsCompleted = action.ActionId == 99,
               ActionDate = action.ActionDate,
           })
           .OrderByDescending(action => action.ActionDate)               
           .FirstOrDefault(),
    })

    // Keep only those parents where the Last Action was completed in time
    .Where(joinResult => joinResult.LastParentAction.IsCompleted
        && joinResult.LastParentAction.ActionDate >= beginDate
        && joinResult.LastParentAction.ActionDate <= endDate)

    // finally: keep only the Parent:
    .Select(joinResult => joinResult.Parent);

1 commentaires

Merci pour votre réponse. Cela semble renvoyer les résultats corrects, mais il est toujours extrêmement lent (annulé après 14 minutes, supprimé toutes les fonctions de distribution et renvoyée dans <1 seconde). Je pensais qu'il y avait un problème avec mon code d'origine et que je pourrais obtenir les données dont j'ai besoin de plus efficacement; Cependant, il semble que le problème soit la façon dont Linq à l'entité génère le SQL, en particulier en ce qui concerne l'ajout de "Cast (... comme numéro (10,0))" autour de toute colonne de la sélection ou de la clause est une colonne entière dans Oracle et une int32 dans mon modèle.



0
votes

Il s'avère, le code que j'avais initialement renvoie ce que je veux, et cela semble être un moyen relativement efficace de le faire. Ma première raison de poser cette question était de voir si 1) mon code était correct de retourner ce que je voulais, et plus important encore 2) était un moyen plus efficace de récupérer les données que je voulais, car mon code prenait plus de 10 minutes. Pour retourner - j'ai pensé à ce que j'ai dû faire quelque chose de mal.

Après avoir essayé tous les merveilleux code fournis (merci beaucoup de Métheny and harald) et à avoir toujours 10 heures de retour de plus de 10 minutes pour 10 rangées, j'ai trébuché sur des postes suggérant que Linq à l'entité peut avoir une performance terrible lorsque le SQL généré contient "Cast (champ en tant que type)", qui s'avère être exactement ce que je vivais. p>

Le code suivant renvoie les résultats souhaités de ma question. P>

var parents = (from p in db.PARENTs
               where p.PARENT_ACTION
                        .Any(pa => pa.ACTION_ID == 99 
                                && pa.ACTION_DATE >= beginDate
                                && pa.ACTION_DATE <= endDate
                                && pa.ACTION_DATE == p.PARENT_ACTION.Max(pam => pam.ACTION_DATE))
              select p);


0 commentaires