Nous avons un tableau de rendez-vous comme indiqué ci-dessous. Chaque rendez-vous doit être classé comme "Nouveau" ou "Suivi". Tout rendez-vous (pour un patient) dans les 30 jours suivant le premier rendez-vous (de ce patient) est un suivi. Après 30 jours, le rendez-vous est à nouveau "Nouveau". Tout rendez-vous dans les 30 jours devient "Suivi".
Je fais actuellement cela en tapant en boucle.
Comment y parvenir sans boucle WHILE?
Table
CREATE TABLE #Appt1 (ApptID INT, PatientID INT, ApptDate DATE)
INSERT INTO #Appt1
SELECT 1,101,'2020-01-05' UNION
SELECT 2,505,'2020-01-06' UNION
SELECT 3,505,'2020-01-10' UNION
SELECT 4,505,'2020-01-20' UNION
SELECT 5,101,'2020-01-25' UNION
SELECT 6,101,'2020-02-12' UNION
SELECT 7,101,'2020-02-20' UNION
SELECT 8,101,'2020-03-30' UNION
SELECT 9,303,'2020-01-28' UNION
SELECT 10,303,'2020-02-02'
fast_forward
curseur soit probablement votre meilleure option, en termes de performances.Réponses:
Vous devez utiliser une requête récursive.
La période de 30 jours est comptée à partir de prev (et non il n'est pas possible de le faire sans récursion / mise à jour / boucle excentrique). C'est pourquoi toutes les réponses existantes en utilisant seulement ont
ROW_NUMBER
échoué.démo db <> violon
Production:
Comment ça fonctionne:
Classe similaire:
Somme conditionnelle sur Oracle - Plafonnement d'une fonction fenêtrée
Fenêtre de session (Azure Stream Analytics)
Exécution de Total jusqu'à ce qu'une condition spécifique soit remplie - Mise à jour Quirky
Addenda
N'utilisez jamais ce code en production!
Cela pourrait être fait en "simple" round (mise à jour excentrique):
Requete:
mise à jour db <> fiddle Quirky
la source
RANGE x PRECEDING
clause.Vous pouvez le faire avec un cte récursif. Vous devez d'abord commander par apptDate au sein de chaque patient. Cela peut être accompli par un cte ordinaire.
Ensuite, dans la partie d'ancrage de votre cte récursif, sélectionnez la première commande pour chaque patient, marquez le statut comme `` nouveau '' et marquez également l'apptDate comme date du `` nouveau '' enregistrement le plus récent.
Dans la partie récursive de votre cte récursif, augmentez jusqu'au prochain rendez-vous, calculez la différence en jours entre le rendez-vous actuel et la «nouvelle» date de rendez-vous la plus récente. S'il est supérieur à 30 jours, marquez-le comme «nouveau» et réinitialisez la date de rendez-vous la plus récente. Sinon, marquez-le comme «suivi» et transmettez simplement les jours existants depuis la nouvelle date de rendez-vous.
Enfin, dans la requête de base, sélectionnez simplement les colonnes souhaitées.
Je dois mentionner que j'ai initialement supprimé cette réponse car la réponse d'Abhijeet Khandagale semblait répondre à vos besoins avec une requête plus simple (après l'avoir un peu retravaillée). Mais avec votre commentaire sur vos besoins commerciaux et vos données d'échantillon ajoutées, j'ai supprimé le mien car je crois que celui-ci répond à vos besoins.
la source
Je ne suis pas sûr que c'est exactement ce que vous avez mis en œuvre. Mais une autre option, qui mérite d'être mentionnée en plus d'utiliser cte, est d'utiliser la table temporaire et la mise à jour en "rounds". Nous allons donc mettre à jour la table temporaire alors que tous les statuts ne sont pas définis correctement et générer le résultat de manière itérative. Nous pouvons contrôler le nombre d'itérations en utilisant simplement une variable locale.
Nous avons donc divisé chaque itération en deux étapes.
Donc
Mise à jour. Lisez le commentaire fourni par Lukasz. C'est de loin beaucoup plus intelligent. Je laisse ma réponse juste comme une idée.
la source
Je pense que l'expression commune récursive est un excellent moyen d'optimiser les requêtes en évitant les boucles, mais dans certains cas, elle peut entraîner de mauvaises performances et doit être évitée si possible.
J'utilise le code ci-dessous pour résoudre le problème et le tester avec plus de valeurs, mais je vous encourage également à le tester avec vos données réelles.
L'idée est assez simple - je veux séparer les enregistrements en groupe (30 jours), dans quel groupe se trouve le plus petit enregistrement
new
, les autres le sontfollow ups
. Vérifiez comment l'instruction est construite:Donc:
* 1.0 / 30
est ajouté+ 0.000001
; aussi, nous utilisons la fonction plafond pour obtenir lesmallest integer greater than, or equal to, the specified numeric expression
C'est ça. Ayant un tel groupe, nous utilisons simplement
ROW_NUMBER
pour trouver notre date de début et le faire commenew
et laisser le reste commefollow ups
.la source
Avec tout le respect que je vous dois et à mon humble avis,
Il n'y a pas beaucoup de gain de performances lors de l'utilisation
Recursive CTE
etWindow Partition function
tout en un.Appid
devrait êtreint identity(1,1)
, ou il devrait être en constante augmentationclustered index
.Outre d'autres avantages, il garantit également que toutes les rangées successives
APPDate
de ce patient doivent être plus grandes.De cette façon, vous pouvez facilement jouer avec
APPID
votre requête, ce qui sera plus efficace que de mettre uninequality
opérateur comme>, <dans APPDate. Mettre l'inequality
opérateur comme>, <dans APPID aidera Sql Optimizer.Il devrait également y avoir deux colonnes de date dans le tableau comme
Comme ce sont les colonnes les plus importantes du tableau le plus important, donc pas beaucoup de conversion, convertissez.
Non clustered index
Peut donc être créé sur AppdateTestez mon script avec d'autres exemples de données et laissez-moi savoir pour quels exemples de données il ne fonctionne pas. Même si cela ne fonctionne pas, je suis sûr qu'il peut être corrigé dans ma logique de script elle-même.
la source
Bien que cela ne soit pas clairement abordé dans la question, il est facile de comprendre que les dates de rendez-vous ne peuvent pas être simplement classées par groupes de 30 jours. Cela n'a aucun sens commercial. Et vous ne pouvez pas non plus utiliser l'ID appt. On peut prendre un nouveau rendez-vous aujourd'hui pour
2020-09-06
. Voici comment j'aborde ce problème. Tout d'abord, obtenez le premier rendez-vous, puis calculez la différence de date entre chaque rendez-vous et le premier rendez-vous. Si c'est 0, réglez sur 'Nouveau'. Si <= 30 'Suivi'. Si> 30, définissez comme «Indécis» et effectuez le prochain tour jusqu'à ce qu'il n'y ait plus «Indécis». Et pour cela, vous avez vraiment besoin d'une boucle while, mais elle ne passe pas par chaque date de rendez-vous, plutôt que quelques ensembles de données. J'ai vérifié le plan d'exécution. Même s'il n'y a que 10 lignes, le coût de la requête est nettement inférieur à celui utilisant le CTE récursif, mais pas aussi bas que la méthode d'addendum de Lukasz Szozda.la source
J'espère que cela t'aidera.
la source
Vous pouvez utiliser une
Case
déclaration .La question est de savoir si cette catégorie devrait être attribuée en fonction de la nomination initiale ou de la précédente. Autrement dit, si un patient a eu trois rendez-vous, devrions-nous comparer le troisième rendez-vous au premier ou au deuxième?
Votre problème énonce le premier, c'est ainsi que j'ai répondu. Si ce n'est pas le cas, vous voudrez l'utiliser
lag
.N'oubliez
DateDiff
pas non plus que les week-ends ne font pas exception. Si cela ne doit être que les jours de la semaine, vous devrez créer votre propre fonction à valeur scalaire.la source
en utilisant la fonction Lag
Démo -> https://rextester.com/TNW43808
la source
apptDate
commeorder by
colonne de lalag
fonction (ce que vous devriez vraiment, car l'ID n'est une garantie de rien), elle peut toujours être facilement rompue en introduisant plus de rendez-vous de suivi. Voir cette démo Rextester par exemple. Bon essai, cependant ...New
et non unFollowUp
. Cela fait plus de 30 jours depuis le premier rendez-vous de ce patient ... Vous devriez compter 30 jours depuis chaqueNew
rendez-vous, puis utiliser àNew
nouveau ...Le mien est correct. Les auteurs étaient incorrects, voir écoulés
la source