Je prépare des données pour un projet de recherche et j'ai des problèmes avec le défi suivant. Si possible, je voudrais tout faire avec SQL ou PL SQL (bien que je sois un vrai novice avec PL).
Supposons que nous ayons le tableau suivant (notez que la périphérie est la ligne souhaitée que j'essaie de créer): < / p> Les colonnes et le défi: p>
3 Réponses :
Comptez simplement le nombre de périodes de démarrage à travers chaque ligne:
select t.*, sum(case when code = 'Start_period' then 1 else 0 end) over (partition by person_id order by date) as period_id from t;
Pourquoi avez-vous écrit "juste compter" mais utilisez "somme"? Utilisez la fonction de comptage à la place.
@ AKK0RD87. . . Le somme () code> fait un compte. En fait,
compte (*) code> n'est pas vraiment nécessaire; C'est juste
somme (1) code>. Si Oracle a appuyé la syntaxe standard, j'utiliserais un filtre
compteur (*) (où code = 'start_period'). . . code>.
Qui parle de "Count (*)"? J'ai dit à propos de "Compte (dossier ... fin)" ou "comptage (décodage (...))".
Voici une réponse en utilisant le match_recognize toujours intéressant. Notez que vous ne devriez pas réellement nommer les colonnes 'code' ou «date», puisqu'ils sont des mots-clés réservés.
match_recognize fonctionne sur plusieurs lignes et essaie de faire correspondre un motif donné. Dans votre cas, vous essayez de faire correspondre un modèle d'un code de départ, suivi de zéro ou d'autres codes d'extrémité non valides / autres codes, suivi d'un code d'extrémité valide. P>
WITH test_vals AS ( SELECT 1 as person_ID,'Start_period' as my_code,to_date('Jan 1','mon dd') as my_date FROM DUAL UNION ALL SELECT 1,'End_period',to_date('Jan 15','mon dd') FROM DUAL UNION ALL SELECT 1,'Random_code1',to_date('Feb 15','mon dd') FROM DUAL UNION ALL SELECT 1,'Random_code2',to_date('Feb 28','mon dd') FROM DUAL UNION ALL SELECT 1,'End_period',to_date('March 31','mon dd') FROM DUAL UNION ALL SELECT 1,'Start_period',to_date('May 31','mon dd') FROM DUAL UNION ALL SELECT 1,'End_period',to_date('June 11','mon dd') FROM DUAL UNION ALL SELECT 1,'End_period',to_date('October 28','mon dd') FROM DUAL ) SELECT m.person_id, m.my_code, m.my_date, m.period_id FROM test_vals t match_recognize( PARTITION BY person_id ORDER BY my_date MEASURES match_number() AS period_id /* Return the match number as the period ID */ ALL ROWS PER match pattern ( start_code /* Match a single start code */ (invalid_end_code | other_code)* /* Match zero or more invalid end codes or other codes */ valid_end_code /* Match a single end code */ ) define start_code AS my_code = 'Start_period', /* Start codes are always valid */ valid_end_code AS my_code = 'End_period' AND (my_date - FIRST(my_date)) > 28, /* End codes are only valid if they come more than 28 days after the start of the pattern match */ invalid_end_code AS my_code = 'End_period' AND (my_date - FIRST(my_date)) <= 28, other_code AS my_code NOT IN ('Start_period', 'End_period') ) m
J'utiliserais des CTE récursives, comme ici: La logique consiste à utiliser la colonne chg code> qui change de la période de direction.
CHG code> est défini sur 1 lorsque le code est
période d'extrémité code> et la date supérieure à la date de début précédemment mémorisée. Dans la période d'étape suivante est incrémenté,
chg code> réinitialiser à zéro et nouveau jeu de date de début. P> p>
Cela semble être un problème des lacunes et des îles. Le site a déjà plusieurs questions sur de tels sujets pour Oracle. Peut-être que l'une de leurs réponses peut vous aider? Vérifiez-les