बिना लूप के क्वेरी


18

हमारे पास नियुक्ति तालिका है जैसा कि नीचे दिखाया गया है। प्रत्येक नियुक्ति को "न्यू" या "फॉलोअप" के रूप में वर्गीकृत किया जाना चाहिए। पहली नियुक्ति के 30 दिनों के भीतर (किसी मरीज के लिए) कोई भी अपॉइंटमेंट फॉलोअप है। 30 दिनों के बाद, नियुक्ति फिर से "नई" है। 30 दिनों के भीतर कोई भी नियुक्ति "फॉलोअप" हो जाती है।

मैं वर्तमान में लूप टाइप करते हुए ऐसा कर रहा हूं।
बिना WHILE लूप के इसे कैसे हासिल करें?

यहाँ छवि विवरण दर्ज करें

तालिका

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' 

मैं आपकी छवि नहीं देख सकता, लेकिन मैं पुष्टि करना चाहता हूं, यदि 3 नियुक्तियां हैं, प्रत्येक 20 दिन एक दूसरे से, आखिरी एक अभी भी 'सही' का पालन कर रही है, क्योंकि भले ही यह पहले से 30 दिन से अधिक हो। यह अभी भी बीच में से 20 दिन से कम है। क्या ये सच है?
pwilcox

@pwilcox नंबर तीसरा नियुक्ति होगी जैसा कि छवि में दिखाया गया है
LCJ

जबकि fast_forwardकर्सर पर लूप शायद आपका सबसे अच्छा विकल्प होगा, प्रदर्शन बुद्धिमान।
डेविड 7:ו --ו मार्कोविट्ज़ ד

जवाबों:


14

आपको पुनरावर्ती क्वेरी का उपयोग करने की आवश्यकता है।

30 दिनों की अवधि को प्रचलित से शुरू किया गया है (और पुनरावृत्ति / विचित्र अद्यतन / लूप के बिना ऐसा करना संभव नहीं है)। यही कारण है कि केवल मौजूदा उत्तर का उपयोग करने में ROW_NUMBERविफल रहा है।

WITH f AS (
  SELECT *, rn = ROW_NUMBER() OVER(PARTITION BY PatientId ORDER BY ApptDate) 
  FROM Appt1
), rec AS (
  SELECT Category = CAST('New' AS NVARCHAR(20)), ApptId, PatientId, ApptDate, rn, startDate = ApptDate
  FROM f
  WHERE rn = 1
  UNION ALL
  SELECT CAST(CASE WHEN DATEDIFF(DAY,  rec.startDate,f.ApptDate) <= 30 THEN N'FollowUp' ELSE N'New' END AS NVARCHAR(20)), 
         f.ApptId,f.PatientId,f.ApptDate, f.rn,
         CASE WHEN DATEDIFF(DAY, rec.startDate, f.ApptDate) <= 30 THEN rec.startDate ELSE f.ApptDate END
  FROM rec
  JOIN f
    ON rec.rn = f.rn - 1
   AND rec.PatientId = f.PatientId
)
SELECT ApptId, PatientId, ApptDate, Category
FROM rec
ORDER BY PatientId, ApptDate;  

db <> फिडेल डेमो

आउटपुट:

+---------+------------+-------------+----------+
| ApptId  | PatientId  |  ApptDate   | Category |
+---------+------------+-------------+----------+
|      1  |       101  | 2020-01-05  | New      |
|      5  |       101  | 2020-01-25  | FollowUp |
|      6  |       101  | 2020-02-12  | New      |
|      7  |       101  | 2020-02-20  | FollowUp |
|      8  |       101  | 2020-03-30  | New      |
|      9  |       303  | 2020-01-28  | New      |
|     10  |       303  | 2020-02-02  | FollowUp |
|      2  |       505  | 2020-01-06  | New      |
|      3  |       505  | 2020-01-10  | FollowUp |
|      4  |       505  | 2020-01-20  | FollowUp |
+---------+------------+-------------+----------+

यह काम किस प्रकार करता है:

  1. f - आरंभिक बिंदु प्राप्त करें (लंगर - प्रति रोगी)
  2. rec - recursibe part, अगर current value और prev के बीच का अंतर है> 30 Patientived के संदर्भ में श्रेणी और प्रारंभिक बिंदु को बदलें
  3. मुख्य - क्रमबद्ध परिणाम प्रदर्शित करें

समान श्रेणी:

ओरेकल पर सशर्त एसयूएम - एक विंडो फ़ंक्शन को कैप करना

सत्र विंडो (Azure Stream Analytics)

जब तक विशिष्ट स्थिति सत्य नहीं है, तब तक कुल चलाना - Quirky अपडेट


परिशिष्ट

कभी भी उत्पादन पर इस कोड का उपयोग न करें!

लेकिन एक अन्य विकल्प, जो cte का उपयोग करने के अलावा ध्यान देने योग्य है, अस्थायी तालिका का उपयोग करना और "राउंड" में अपडेट करना है

यह "सिंगल" राउंड (क्वर्की अपडेट) में किया जा सकता है:

CREATE TABLE Appt_temp (ApptID INT , PatientID INT, ApptDate DATE, Category NVARCHAR(10))

INSERT INTO Appt_temp(ApptId, PatientId, ApptDate)
SELECT ApptId, PatientId, ApptDate
FROM Appt1;

CREATE CLUSTERED INDEX Idx_appt ON Appt_temp(PatientID, ApptDate);

प्रश्न:

DECLARE @PatientId INT = 0,
        @PrevPatientId INT,
        @FirstApptDate DATE = NULL;

UPDATE Appt_temp
SET  @PrevPatientId = @PatientId
    ,@PatientId     = PatientID 
    ,@FirstApptDate = CASE WHEN @PrevPatientId <> @PatientId THEN ApptDate
                           WHEN DATEDIFF(DAY, @FirstApptDate, ApptDate)>30 THEN ApptDate
                           ELSE @FirstApptDate
                      END
    ,Category       = CASE WHEN @PrevPatientId <> @PatientId THEN 'New'
                           WHEN @FirstApptDate = ApptDate THEN 'New'
                           ELSE 'FollowUp' 
                      END
FROM Appt_temp WITH(INDEX(Idx_appt))
OPTION (MAXDOP 1);

SELECT * FROM  Appt_temp ORDER BY PatientId, ApptDate;

db <> फिडल क्वर्की अपडेट


1
आपका तर्क मेरा बहुत समान है। क्या आप किसी महत्वपूर्ण अंतर का वर्णन कर सकते हैं?
प्वॉल्क्सॉक्स

@pwilcox जब मैंने यह उत्तर लिखा तो हर मौजूदा व्यक्ति सरल रो_नंबर का उपयोग कर रहा था जो काम नहीं कर रहा था, यही कारण है कि मैंने अपना स्वयं का संस्करण प्रदान किया
लुकाज़ स्ज़ोज़ा

हाँ, मैं जवाब के साथ बहुत जल्दी था। उस पर टिप्पणी करने के लिए Thx।
इरदिस

2
मेरा मानना ​​है कि rcte इसके लिए एकमात्र समाधान है जब तक SQL सर्वर RANGE x PRECEDINGक्लॉज को सही तरीके से लागू नहीं करता है।
सलमान ए

1
@LCJ Quirky अपडेट "अनकम्डर्ड" व्यवहार पर आधारित है और यह बिना किसी नोटिस के किसी भी क्षण में बदल सकता है ( red-gate.com/simple-talk/sql/learn-sql-server/… )
Lukhz Szozda

5

आप एक पुनरावर्ती cte के साथ ऐसा कर सकते हैं। आपको पहले प्रत्येक रोगी के भीतर apptDate द्वारा आदेश देना चाहिए। यह एक रन-ऑफ-द-मिल सीटीई द्वारा पूरा किया जा सकता है।

फिर, अपने पुनरावर्ती सीएटी के एंकर भाग में, प्रत्येक रोगी के लिए पहले आदेश का चयन करें, स्थिति को 'नए' के ​​रूप में चिह्नित करें, और सबसे हाल ही के 'नए' रिकॉर्ड की तारीख के रूप में भी ऐपेट को चिह्नित करें।

अपने पुनरावर्ती cte के पुनरावर्ती भाग में, अगली नियुक्ति में वृद्धि, वर्तमान नियुक्ति और सबसे हाल की 'नई' नियुक्ति तिथि के बीच के दिनों में अंतर की गणना करें। यदि यह 30 दिनों से अधिक है, तो इसे 'नया' चिह्नित करें और हाल ही की नई नियुक्ति तिथि को रीसेट करें। अन्यथा इसे 'फॉलो अप' के रूप में चिह्नित करें और नई नियुक्ति तिथि के बाद से मौजूदा दिनों के साथ गुजरें।

आधार क्वेरी में, अंतिम रूप से, इच्छित कॉलम चुनें।

with orderings as (

    select       *, 
                 rn = row_number() over(
                     partition by patientId 
                     order by apptDate
                 ) 
    from         #appt1 a

),

markings as (

    select       apptId, 
                 patientId, 
                 apptDate, 
                 rn, 
                 type = convert(varchar(10),'new'),
                 dateOfNew = apptDate
    from         orderings 
    where        rn = 1

    union all
    select       o.apptId, o.patientId, o.apptDate, o.rn,
                 type = convert(varchar(10),iif(ap.daysSinceNew > 30, 'new', 'follow up')),
                 dateOfNew = iif(ap.daysSinceNew > 30, o.apptDate, m.dateOfNew)
    from         markings m
    join         orderings o 
                     on m.patientId = o.patientId 
                     and m.rn + 1 = o.rn
    cross apply  (select daysSinceNew = datediff(day, m.dateOfNew, o.apptDate)) ap

)

select    apptId, patientId, apptDate, type
from      markings
order by  patientId, rn;

मुझे यह उल्लेख करना चाहिए कि मैंने शुरू में इस उत्तर को हटा दिया था क्योंकि अभिजीत खंडगले का उत्तर आपकी आवश्यकताओं को एक सरल प्रश्न के साथ पूरा करने के बाद लगता था (थोड़ा सा काम करने के बाद)। लेकिन आपकी व्यावसायिक आवश्यकता और आपके जोड़े गए नमूना डेटा के बारे में आपकी टिप्पणी के साथ, मैंने मेरा अविकसित कर दिया क्योंकि मेरा मानना ​​है कि यह आपकी आवश्यकताओं को पूरा करता है।


4

मुझे यकीन नहीं है कि यह वही है जो आपने लागू किया है। लेकिन एक अन्य विकल्प, जो cte का उपयोग करने के अलावा ध्यान देने योग्य है, अस्थायी तालिका का उपयोग करना और "राउंड" में अपडेट करना है। इसलिए हम अस्थायी तालिका को अद्यतन करने जा रहे हैं, जबकि सभी स्थितियां सही तरीके से सेट नहीं की गई हैं और परिणामी रूप से इसका निर्माण किया जा रहा है। हम केवल स्थानीय चर का उपयोग करके पुनरावृति की संख्या को नियंत्रित कर सकते हैं।

इसलिए हम प्रत्येक पुनरावृत्ति को दो चरणों में विभाजित करते हैं।

  1. सभी फ़ॉलोअप मान सेट करें जो नए रिकॉर्ड के पास हैं। यह सिर्फ सही फिल्टर का उपयोग करने के लिए बहुत आसान है।
  2. बाकी रिकॉर्ड्स के लिए जो हैसियत सेट नहीं है, हम पहले एक ही रोगी के साथ समूह में चुन सकते हैं। और कहते हैं कि वे नए हैं क्योंकि वे पहले चरण से संसाधित नहीं हुए हैं।

इसलिए

CREATE TABLE #Appt2 (ApptID INT, PatientID INT, ApptDate DATE, AppStatus nvarchar(100))

select * from #Appt1
insert into #Appt2 (ApptID, PatientID, ApptDate, AppStatus)
select a1.ApptID, a1.PatientID, a1.ApptDate, null from #Appt1 a1
declare @limit int = 0;

while (exists(select * from #Appt2 where AppStatus IS NULL) and @limit < 1000)
begin
  set @limit = @limit+1;
  update a2
  set
    a2.AppStatus = IIF(exists(
        select * 
        from #Appt2 a 
        where 
          0 > DATEDIFF(day, a2.ApptDate, a.ApptDate) 
          and DATEDIFF(day, a2.ApptDate, a.ApptDate) > -30 
          and a.ApptID != a2.ApptID 
          and a.PatientID = a2.PatientID
          and a.AppStatus = 'New'
          ), 'Followup', a2.AppStatus)
  from #Appt2 a2

  --select * from #Appt2

  update a2
  set a2.AppStatus = 'New'
  from #Appt2 a2 join (select a.*, ROW_NUMBER() over (Partition By PatientId order by ApptId) rn from (select * from #Appt2 where AppStatus IS NULL) a) ar
  on a2.ApptID = ar.ApptID
  and ar.rn = 1

  --select * from #Appt2

end

select * from #Appt2 order by PatientID, ApptDate

drop table #Appt1
drop table #Appt2

अपडेट करें। लुकाज़ द्वारा प्रदान की गई टिप्पणी पढ़ें। यह अब तक का रास्ता है। मैं अपना जवाब सिर्फ एक विचार के रूप में छोड़ता हूं।


4

मेरा मानना ​​है कि पुनरावर्ती सामान्य अभिव्यक्ति लूप से बचने वाले प्रश्नों को अनुकूलित करने का एक शानदार तरीका है, लेकिन कुछ मामलों में यह खराब प्रदर्शन का कारण बन सकता है और यदि संभव हो तो इसे टाला जाना चाहिए।

मैं मुद्दे को हल करने के लिए नीचे दिए गए कोड का उपयोग करता हूं और यह अधिक मूल्यों का परीक्षण करेगा, लेकिन आपको इसे अपने वास्तविक डेटा के साथ परीक्षण करने के लिए प्रोत्साहित करता है।

WITH DataSource AS
(
    SELECT *
          ,CEILING(DATEDIFF(DAY, MIN([ApptDate]) OVER (PARTITION BY [PatientID]), [ApptDate]) * 1.0 / 30 + 0.000001) AS [GroupID]
    FROM #Appt1
)
SELECT *
     ,IIF(ROW_NUMBER() OVER (PARTITION BY [PatientID], [GroupID] ORDER BY [ApptDate]) = 1, 'New', 'Followup')
FROM DataSource
ORDER BY [PatientID]
        ,[ApptDate];

यहाँ छवि विवरण दर्ज करें

यह विचार बहुत सरल है - मैं समूह (30 दिन) में अलग-अलग रिकॉर्ड चाहता हूं, जिस समूह में सबसे छोटा रिकॉर्ड है new, अन्य हैं follow ups। जाँचें कि कथन कैसे बनाया गया है:

SELECT *
      ,DATEDIFF(DAY, MIN([ApptDate]) OVER (PARTITION BY [PatientID]), [ApptDate])
      ,DATEDIFF(DAY, MIN([ApptDate]) OVER (PARTITION BY [PatientID]), [ApptDate]) * 1.0 / 30
      ,CEILING(DATEDIFF(DAY, MIN([ApptDate]) OVER (PARTITION BY [PatientID]), [ApptDate]) * 1.0 / 30 + 0.000001) 
FROM #Appt1
ORDER BY [PatientID]
        ,[ApptDate];

यहाँ छवि विवरण दर्ज करें

इसलिए:

  1. सबसे पहले, हम प्रत्येक समूह के लिए पहली तिथि प्राप्त कर रहे हैं, और वर्तमान एक के साथ दिनों में अंतर की गणना कर रहे हैं
  2. फिर, हम समूह प्राप्त करना चाहते हैं - * 1.0 / 30 जोड़ा जाता है
  3. 30, 60, 90, आदि दिनों से हमें पूरे नंबर मिल रहे हैं और हम एक नई अवधि शुरू करना चाहते हैं, मैंने जोड़ा है + 0.000001; भी, हम पाने के लिए छत समारोह का उपयोग कर रहे हैंsmallest integer greater than, or equal to, the specified numeric expression

बस। इस तरह के समूह होने से हम ROW_NUMBERअपनी शुरुआत की तारीख का पता लगाने के लिए इसका इस्तेमाल करते हैं और इसे newबाकी के रूप में छोड़ देते हैं follow ups


2
खैर, सवाल थोड़ा अलग है और यह बहुत ही महत्वपूर्ण है। लेकिन यह एक अच्छा उदाहरण है कि कैसे tumbling विंडो
Lukasz Szozda

यह प्रदर्शन के बारे में भी है। मेरा मानना ​​है कि पुनरावर्ती को धीमा होना चाहिए।
१६:०६ पर गत

3

हर किसी के प्रति और IMHO के सम्मान के साथ,

There is not much difference between While LOOP and Recursive CTE in terms of RBAR

उपयोग करते समय Recursive CTEऔर Window Partition functionसभी में बहुत अधिक प्रदर्शन नहीं होता है ।

Appidहोना चाहिए int identity(1,1), या यह कभी भी बढ़ जाना चाहिए clustered index

अन्य लाभ के अलावा यह भी सुनिश्चित करता है कि APPDateउस रोगी की सभी क्रमिक पंक्ति अधिक से अधिक होनी चाहिए।

इस तरह आप APPIDअपनी क्वेरी में आसानी से खेल सकते हैं, जो inequalityऑपरेटर, जैसे कि>, <APPDate में डालने से अधिक कुशल होगा । inequalityपरिचालक जैसे>, <APPID में डालने से Sql Optimizer को सहायता मिलेगी।

साथ ही टेबल में दो डेट का कॉलम होना चाहिए जैसे

APPDateTime datetime2(0) not null,
Appdate date not null

चूंकि ये सबसे महत्वपूर्ण तालिका में सबसे महत्वपूर्ण स्तंभ हैं, इसलिए बहुत अधिक नहीं डाले जाते हैं, रूपांतरित होते हैं।

तो Non clustered indexAppdate पर बनाया जा सकता है

Create NonClustered index ix_PID_AppDate_App  on APP (patientid,APPDate) include(other column which is not i predicate except APPID)

अन्य नमूना डेटा के साथ मेरी स्क्रिप्ट का परीक्षण करें और पता है कि किस नमूना डेटा के लिए यह काम नहीं कर रहा है। यहां तक ​​कि अगर यह काम नहीं करता है, तो मुझे यकीन है कि यह मेरे स्क्रिप्ट तर्क में ही ठीक हो सकता है।

CREATE TABLE #Appt1 (ApptID INT, PatientID INT, ApptDate DATE)
INSERT INTO #Appt1
SELECT  1,101,'2020-01-05'  UNION ALL
SELECT  2,505,'2020-01-06'  UNION ALL
SELECT  3,505,'2020-01-10'  UNION ALL
SELECT  4,505,'2020-01-20'  UNION ALL
SELECT  5,101,'2020-01-25'  UNION ALL
SELECT  6,101,'2020-02-12'  UNION ALL
SELECT  7,101,'2020-02-20'  UNION ALL
SELECT  8,101,'2020-03-30'  UNION ALL
SELECT  9,303,'2020-01-28'  UNION ALL
SELECT  10,303,'2020-02-02' 

;With CTE as
(
select a1.* ,a2.ApptDate as NewApptDate
from #Appt1 a1
outer apply(select top 1 a2.ApptID ,a2.ApptDate
from #Appt1 A2 
where a1.PatientID=a2.PatientID and a1.ApptID>a2.ApptID 
and DATEDIFF(day,a2.ApptDate, a1.ApptDate)>30
order by a2.ApptID desc )A2
)
,CTE1 as
(
select a1.*, a2.ApptDate as FollowApptDate
from CTE A1
outer apply(select top 1 a2.ApptID ,a2.ApptDate
from #Appt1 A2 
where a1.PatientID=a2.PatientID and a1.ApptID>a2.ApptID 
and DATEDIFF(day,a2.ApptDate, a1.ApptDate)<=30
order by a2.ApptID desc )A2
)
select  * 
,case when FollowApptDate is null then 'New' 
when NewApptDate is not null and FollowApptDate is not null 
and DATEDIFF(day,NewApptDate, FollowApptDate)<=30 then 'New'
else 'Followup' end
 as Category
from cte1 a1
order by a1.PatientID

drop table #Appt1

3

हालाँकि यह प्रश्न में स्पष्ट रूप से संबोधित नहीं है, यह पता लगाना आसान है कि नियुक्ति की तारीखों को केवल 30-दिन के समूहों द्वारा वर्गीकृत नहीं किया जा सकता है। यह कोई व्यावसायिक समझ नहीं है। और आप appt id का भी उपयोग नहीं कर सकते हैं। कोई आज के लिए एक नई नियुक्ति कर सकता है2020-09-06। यहाँ मैं इस मुद्दे को कैसे संबोधित करता हूं। सबसे पहले, पहली नियुक्ति प्राप्त करें, फिर प्रत्येक नियुक्ति और पहले एप्ट के बीच की तारीख के अंतर की गणना करें। यदि यह 0 है, तो 'नया' पर सेट करें। यदि <= 30 'फॉलोअप'। यदि> 30, 'अनिर्धारित' के रूप में सेट किया गया है और अगले दौर की जांच तब तक करें जब तक कि कोई 'अनिर्धारित' न हो। और उसके लिए, आपको वास्तव में थोड़ी देर के लूप की आवश्यकता होती है, लेकिन यह प्रत्येक नियुक्ति तिथि के माध्यम से लूप नहीं करता है, बल्कि केवल कुछ डेटासेट। मैंने निष्पादन योजना की जाँच की। भले ही केवल 10 पंक्तियाँ हों, फिर भी क्वेरी लागत पुनरावर्ती CTE का उपयोग करते हुए की तुलना में काफी कम है, लेकिन लुकाज़ स्ज़ोज़ा के परिशिष्ट विधि से कम नहीं है।

IF OBJECT_ID('tempdb..#TEMPTABLE') IS NOT NULL DROP TABLE #TEMPTABLE
SELECT ApptID, PatientID, ApptDate
    ,CASE WHEN (DATEDIFF(DAY, MIN(ApptDate) OVER (PARTITION BY PatientID), ApptDate) = 0) THEN 'New' 
    WHEN (DATEDIFF(DAY, MIN(ApptDate) OVER (PARTITION BY PatientID), ApptDate) <= 30) THEN 'Followup'
    ELSE 'Undecided' END AS Category
INTO #TEMPTABLE
FROM #Appt1

WHILE EXISTS(SELECT TOP 1 * FROM #TEMPTABLE WHERE Category = 'Undecided') BEGIN
    ;WITH CTE AS (
        SELECT ApptID, PatientID, ApptDate 
            ,CASE WHEN (DATEDIFF(DAY, MIN(ApptDate) OVER (PARTITION BY PatientID), ApptDate) = 0) THEN 'New' 
            WHEN (DATEDIFF(DAY, MIN(ApptDate) OVER (PARTITION BY PatientID), ApptDate) <= 30) THEN 'Followup'
            ELSE 'Undecided' END AS Category    
        FROM #TEMPTABLE
        WHERE Category = 'Undecided'
    )
    UPDATE #TEMPTABLE
    SET Category = CTE.Category
    FROM #TEMPTABLE t
        LEFT JOIN CTE ON CTE.ApptID = t.ApptID
    WHERE t.Category = 'Undecided'
END

SELECT ApptID, PatientID, ApptDate, Category 
FROM #TEMPTABLE

2

उम्मीद है इससे आपको मदद मिलेगी।

WITH CTE AS
(
    SELECT #Appt1.*, RowNum = ROW_NUMBER() OVER (PARTITION BY PatientID ORDER BY ApptDate, ApptID) FROM #Appt1
)

SELECT A.ApptID , A.PatientID , A.ApptDate ,
Expected_Category = CASE WHEN (DATEDIFF(MONTH, B.ApptDate, A.ApptDate) > 0) THEN 'New' 
WHEN (DATEDIFF(DAY, B.ApptDate, A.ApptDate) <= 30) then 'Followup' 
ELSE 'New' END
FROM CTE A
LEFT OUTER JOIN CTE B on A.PatientID = B.PatientID 
AND A.rownum = B.rownum + 1
ORDER BY A.PatientID, A.ApptDate

पठनीय प्रारूप में संपादन कोड के लिए धन्यवाद @ x00, मैं उत्तर देने के लिए अपने सेलफोन का उपयोग कर रहा हूं ताकि उचित इंडेंटेशन देने में सक्षम न हो।
अभिजीत खंडागले

मुझे लगता है कि यह सही उत्तर है। लेकिन यह एक खराब गुणवत्ता वाला उत्तर है जिसमें इसे समझाया नहीं गया है और कोड में एक अनावश्यक बाहरी क्वेरी है जब आंतरिक भाग का एक संशोधन ठीक होगा। यदि आप उन मुद्दों को हल कर सकते हैं तो मुझे आपको वोट करने में खुशी होगी।
प्वॉल्क्सॉक्स

1
@pwilcox, बहुमूल्य सुझाव के लिए धन्यवाद, मैंने उत्तर संपादित किया है और इसे अभी पोस्ट किया है। जैसा कि मैं यात्रा कर रहा हूं और मेरे पास लैपटॉप नहीं है, मैं एक-दो दिन में स्पष्टीकरण पोस्ट करूंगा।
अभिजीत खंडागले

1
@AbhijeetKhandagale यह पूरी तरह से व्यावसायिक आवश्यकता को पूरा नहीं करता है। मैंने प्रश्न में एक असफल परिदृश्य जोड़ा है। रोगी के लिए 303, फरवरी 2 अपॉइंटमेंट का पालन किया जाना चाहिए; लेकिन आपकी क्वेरी बताती है कि यह "नया" है
LCJ

1

आप एक Caseबयान का उपयोग कर सकते हैं ।

select 
      *, 
      CASE 
          WHEN DATEDIFF(d,A1.ApptDate,A2.ApptDate)>30 THEN 'New' 
          ELSE 'FollowUp' 
      END 'Category'
from 
      (SELECT PatientId, MIN(ApptId) 'ApptId', MIN(ApptDate) 'ApptDate' FROM #Appt1 GROUP BY PatientID)  A1, 
      #Appt1 A2 
where 
     A1.PatientID=A2.PatientID AND A1.ApptID<A2.ApptID

सवाल यह है कि क्या इस श्रेणी को प्रारंभिक नियुक्ति के आधार पर सौंपा जाना चाहिए, या पहले से? यही है, अगर एक रोगी के पास तीन नियुक्तियां हैं, तो क्या हमें तीसरी नियुक्ति की तुलना पहले या दूसरे से करनी चाहिए?

आपको समस्या पहले बताती है, जो मैंने उत्तर दिया है। यदि ऐसा नहीं है, तो आप उपयोग करना चाहते हैं lag

इसके अलावा, ध्यान रखें कि DateDiffसप्ताहांत के लिए अपवाद नहीं बनता है। यदि यह केवल कार्यदिवस होना चाहिए, तो आपको अपना स्केलर-वैल्यूड फंक्शन बनाना होगा।


1
यह दो अनुक्रमिक नियुक्तियों को जोड़ता नहीं है, यह लिंक सभी निम्नलिखित नियुक्तियों के लिए 1 को जोड़ता है और उन सभी के बीच के दिनों की गणना करता है। आप इस तरह से बहुत सारे रिकॉर्ड लौटा देंगे, क्योंकि
एप् ट

अच्छी बात। मैंने A1 के लिए एक सबसिलेक्ट करने के लिए अपने उत्तर को अपडेट किया।
उपयोगकर्ता

1
यह अपेक्षित परिणाम नहीं देता है। 20 फरवरी की नियुक्ति "फॉलोअप" होनी चाहिए
LCJ

प्रश्न अस्पष्ट है ... पोस्टर विवरण यह है: "किसी भी नियुक्ति (एक मरीज के लिए) पहली नियुक्ति के 30 दिनों के भीतर (उस मरीज की) अनुवर्ती है। 30 दिनों के बाद, नियुक्ति फिर से" नई "है। किसी भी नियुक्ति के लिए 30 दिन की छूट है। "फॉलोअप" बनें। 5 फरवरी को निश्चित रूप से 20 फरवरी, यानी नई से 30 दिनों से अधिक दूर है। यह 12 फरवरी से 30 दिन दूर नहीं है। मैं उसके लिखे हुए समाधान का प्रस्ताव देता हूं, न कि आपूर्ति की गई तालिका का। यदि उपयोगकर्ता तालिका की आपूर्ति के साथ संरेखित करना चाहते हैं, तो उन्हें अंतराल का उपयोग करना चाहिए। उन्हें यह भी स्पष्ट करना चाहिए ...
उपयोगकर्ता 19

1

लाग समारोह का उपयोग करना


select  apptID, PatientID , Apptdate ,  
    case when date_diff IS NULL THEN 'NEW' 
         when date_diff < 30 and (date_diff_2 IS NULL or date_diff_2 < 30) THEN  'Follow Up'
         ELSE 'NEW'
    END AS STATUS FROM 
(
select 
apptID, PatientID , Apptdate , 
DATEDIFF (day,lag(Apptdate) over (PARTITION BY PatientID order by ApptID asc),Apptdate) date_diff ,
DATEDIFF(day,lag(Apptdate,2) over (PARTITION BY PatientID order by ApptID asc),Apptdate) date_diff_2
  from #Appt1
) SRC

डेमो -> https://rextester.com/TNW43808


2
यह वर्तमान नमूना डेटा पर काम करता है, लेकिन एक अलग नमूना डेटा दिए गए गलत परिणाम प्राप्त कर सकता है। यहां तक ​​कि अगर आप फ़ंक्शन apptDateके order byकॉलम के रूप में उपयोग करते lagहैं (जो आपको वास्तव में आईडी होना चाहिए, किसी भी चीज की गारंटी नहीं है), यह अभी भी अधिक फॉलोअप नियुक्तियों को पेश करके आसानी से तोड़ा जा सकता है। उदाहरण के लिए यह Rextester डेमो देखें । अच्छी कोशिश, हालाँकि ...
ज़ोहर पे

धन्यवाद। आईडी के बजाय तारीख का उपयोग करना चाहिए था। लेकिन यह apptID के लिए गलत क्यों है = 6 25.01.2020 - 12.02.2020 -> 18 दिन -> का पालन करें।
दिग्विजय एस

2
क्योंकि यह एक होना चाहिए Newऔर एक नहीं होना चाहिए FollowUp। उस मरीज की पहली नियुक्ति के 30 दिनों से अधिक समय है ... आपको प्रत्येक Newनियुक्ति के बाद से 30 दिनों की गणना करनी चाहिए और फिर Newदोबारा उपयोग करना चाहिए ...
ज़ोहर पेलेड

हाँ। धन्यवाद। :( तिथि की वैध अवधि की जांच के लिए एक नया बनाने की आवश्यकता है।
दिग्विजय एस

1
with cte
as
(
select 
tmp.*, 
IsNull(Lag(ApptDate) Over (partition by PatientID Order by  PatientID,ApptDate),ApptDate) PriorApptDate
 from #Appt1 tmp
)
select 
PatientID, 
ApptDate, 
PriorApptDate, 
DateDiff(d,PriorApptDate,ApptDate) Elapsed,
Case when DateDiff(d,PriorApptDate,ApptDate)>30 
or DateDiff(d,PriorApptDate,ApptDate)=0 then 'New' else 'Followup'   end Category   from cte

मेरा सही है। लेखक गलत थे, देखते हैं

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.