Permintaan tanpa WHILE Loop

18

Kami memiliki tabel perjanjian seperti yang ditunjukkan di bawah ini. Setiap janji temu harus dikategorikan sebagai "Baru" atau "Tindak Lanjut". Setiap janji temu (untuk seorang pasien) dalam waktu 30 hari sejak perjanjian pertama (dari pasien itu) adalah Tindak Lanjut. Setelah 30 hari, janji temu kembali "Baru". Setiap janji dalam 30 hari menjadi "Tindak Lanjut".

Saat ini saya melakukan ini dengan mengetikkan loop sementara.
Bagaimana mencapai ini tanpa WHILE loop?

masukkan deskripsi gambar di sini

Meja

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' 
LCJ
sumber
Saya tidak dapat melihat gambar Anda, tetapi saya ingin mengkonfirmasi, jika ada 3 janji, masing-masing 20 hari dari satu sama lain, yang terakhir masih 'tindak lanjut' benar, karena meskipun lebih dari 30 hari dari yang pertama, masih kurang dari 20 hari dari tengah. Apakah ini benar?
pwilcox
@ pwilcox No. Yang ketiga akan menjadi janji baru seperti yang ditunjukkan pada gambar
LCJ
Sementara fast_forwardkursor di atas kursor mungkin akan menjadi pilihan terbaik Anda, kinerja bijaksana.
David Markודו Markovitz

Jawaban:

14

Anda perlu menggunakan permintaan rekursif.

Periode 30 hari dihitung mulai dari prev (dan tidak mungkin untuk melakukannya tanpa rekursi / pembaruan unik / loop). Itu sebabnya semua jawaban yang ada hanya menggunakan ROW_NUMBERgagal.

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 <> demo biola

Keluaran:

+---------+------------+-------------+----------+
| 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 |
+---------+------------+-------------+----------+

Bagaimana itu bekerja:

  1. f - dapatkan titik awal (jangkar - per setiap PatientId)
  2. bagian rec - recursibe, jika perbedaan antara nilai saat ini dan prev adalah> 30 ubah kategori dan titik awal, dalam konteks PatientId
  3. Main - display resultset yang diurutkan

Kelas serupa:

SUM bersyarat pada Oracle - Capping fungsi windowed

Jendela sesi (Analisis Azure Stream)

Menjalankan Total hingga kondisi tertentu benar - Pembaruan unik


Tambahan

Jangan pernah menggunakan kode ini untuk produksi!

Tetapi opsi lain, yang layak disebutkan selain menggunakan cte, adalah menggunakan tabel temp dan memperbarui dalam "putaran"

Itu bisa dilakukan dalam putaran "tunggal" (pembaruan unik):

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);

Pertanyaan:

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 <> fiddle Pembaruan unik

Lukasz Szozda
sumber
1
logika Anda terlihat sangat mirip dengan logika saya. Bisakah Anda menggambarkan perbedaan yang signifikan?
pwilcox
@ pwilcox Ketika saya menulis jawaban ini, setiap jawaban yang ada menggunakan row_number sederhana yang tidak berfungsi, inilah mengapa saya menyediakan versi saya sendiri
Lukasz Szozda
Ya, saya terlalu cepat dengan jawabannya. Terima kasih untuk mengomentari itu.
Irdis
2
Saya percaya rcte adalah satu-satunya solusi untuk ini sampai SQL server mengimplementasikan RANGE x PRECEDINGklausa dengan benar .
Salman A
1
@LCJ Pembaruan unik didasarkan pada perilaku "tidak berdokumen" dan dapat berubah kapan saja tanpa pemberitahuan ( red-gate.com/simple-talk/sql/learn-sql-server/… )
Lukasz Szozda
5

Anda bisa melakukan ini dengan cyt rekursif. Anda harus memesan terlebih dahulu dengan apptDate dalam setiap pasien. Itu bisa dicapai dengan run-of-the-mill cte.

Kemudian, di bagian jangkar cyt rekursif Anda, pilih pemesanan pertama untuk setiap pasien, tandai status sebagai 'baru', dan juga tandai apptDate sebagai tanggal dari catatan 'baru' terbaru.

Dalam bagian rekursif dari cyt rekursif Anda, kenaikan janji temu berikutnya, hitung selisih hari antara janji temu saat ini dan tanggal janji temu 'baru' terbaru. Jika lebih dari 30 hari, tandai 'baru' dan setel ulang tanggal janji temu baru. Kalau tidak, tandai sebagai 'tindak lanjut' dan hanya meneruskan hari-hari yang ada sejak tanggal janji baru.

Akhirnya, dalam permintaan dasar, cukup pilih kolom yang Anda inginkan.

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;

Saya harus menyebutkan bahwa saya awalnya menghapus jawaban ini karena jawaban Abhijeet Khandagale tampaknya memenuhi kebutuhan Anda dengan permintaan yang lebih sederhana (setelah sedikit mengolahnya). Tetapi dengan komentar Anda kepadanya tentang kebutuhan bisnis Anda dan data sampel tambahan Anda, saya membatalkan pesanan saya karena percaya ini memenuhi kebutuhan Anda.

pwilcox
sumber
4

Saya tidak yakin itu persis seperti yang Anda terapkan. Tetapi opsi lain, yang layak disebutkan selain menggunakan cte, adalah menggunakan tabel temp dan memperbarui dalam "putaran". Jadi kita akan memperbarui tabel temp sementara semua status tidak diatur dengan benar dan membangun hasil dengan cara yang berulang. Kita dapat mengontrol jumlah iterasi menggunakan hanya variabel lokal.

Jadi kami membagi setiap iterasi menjadi dua tahap.

  1. Tetapkan semua nilai Tindak Lanjut yang dekat dengan Catatan baru. Itu cukup mudah dilakukan hanya dengan menggunakan filter yang tepat.
  2. Untuk sisa catatan yang tidak memiliki status yang ditetapkan, kita dapat memilih pertama dalam grup dengan PatientID yang sama. Dan katakan bahwa mereka baru karena mereka tidak diproses oleh tahap pertama.

Begitu

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

Memperbarui. Baca komentar yang diberikan oleh Lukasz. Jauh lebih pintar. Saya meninggalkan jawaban saya hanya sebagai ide.

Irdis
sumber
4

Saya percaya ungkapan umum rekursif adalah cara yang bagus untuk mengoptimalkan kueri menghindari loop, tetapi dalam beberapa kasus dapat menyebabkan kinerja yang buruk dan harus dihindari jika mungkin.

Saya menggunakan kode di bawah ini untuk menyelesaikan masalah dan mengujinya akan lebih banyak nilai, tetapi mendorong Anda untuk mengujinya dengan data nyata Anda juga.

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];

masukkan deskripsi gambar di sini

Idenya cukup sederhana - Saya ingin memisahkan catatan dalam kelompok (30 hari), di mana kelompok catatan terkecil adalah new, yang lain adalah follow ups. Periksa bagaimana pernyataan itu dibuat:

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];

masukkan deskripsi gambar di sini

Begitu:

  1. pertama, kami mendapatkan tanggal pertama, untuk setiap grup dan menghitung perbedaan dalam hari dengan yang sekarang
  2. lalu, kami ingin mendapatkan grup - * 1.0 / 30ditambahkan
  3. Adapun 30, 60, 90, dll hari kami mendapatkan seluruh nomor dan kami ingin memulai periode baru, saya telah menambahkan + 0.000001; juga, kami menggunakan fungsi plafon untuk mendapatkansmallest integer greater than, or equal to, the specified numeric expression

Itu dia. Memiliki grup seperti itu, kami cukup gunakan ROW_NUMBERuntuk menemukan tanggal mulai kami dan menjadikannya sebagai newdan meninggalkan sisanya sebagai follow ups.

Gotqn
sumber
2
Nah, pertanyaannya sedikit berbeda dan pendekatan ini terlalu menyederhanakan. Tapi itu adalah contoh yang bagus bagaimana menerapkan jendela jatuh
Lukasz Szozda
Ini tentang kinerja juga. Saya percaya rekursif harus lebih lambat.
Gotqn
3

Dengan hormat kepada semua orang dan di IMHO,

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

Tidak ada banyak peningkatan kinerja saat menggunakan Recursive CTEdan Window Partition functionsemuanya.

Appidharus int identity(1,1), atau harus semakin meningkat clustered index.

Selain manfaat lainnya, ini juga memastikan bahwa semua deretan APPDatepasien yang berurutan harus lebih besar.

Dengan cara ini Anda dapat dengan mudah bermain APPIDdalam kueri yang akan lebih efisien daripada menempatkan inequalityoperator seperti>, <di APPDate. Menempatkan inequalityoperator seperti>, <dalam APPID akan membantu Pengoptimal Sql.

Juga harus ada dua kolom tanggal dalam tabel seperti

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

Karena ini adalah kolom paling penting di tabel paling penting, jadi tidak banyak pemain, konversi.

Jadi Non clustered indexbisa dibuat di Appdate

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

Tes skrip saya dengan data sampel lain dan biar tahu sampel data mana yang tidak berfungsi. Bahkan jika itu tidak berhasil maka saya yakin itu bisa diperbaiki dalam logika skrip saya sendiri.

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
KumarHarsh
sumber
3

Meskipun tidak secara jelas dibahas dalam pertanyaan, mudah untuk mengetahui bahwa tanggal penunjukan tidak dapat dengan mudah dikategorikan oleh kelompok 30 hari. Itu tidak masuk akal bisnis. Dan Anda tidak dapat menggunakan id appt juga. Anda dapat membuat janji baru hari ini untuk2020-09-06. Inilah cara saya mengatasi masalah ini. Pertama, dapatkan janji temu pertama, lalu hitung selisih tanggal antara setiap janji temu dan appt pertama. Jika 0, atur ke 'Baru'. Jika <= 30 'Tindak Lanjut'. Jika> 30, tetapkan sebagai 'Bimbang' dan lakukan pemeriksaan putaran berikutnya hingga tidak ada lagi 'Bimbang'. Dan untuk itu, Anda benar-benar membutuhkan loop sementara, tetapi tidak mengulangi setiap tanggal janji, melainkan hanya beberapa set data. Saya memeriksa rencana eksekusi. Meskipun hanya ada 10 baris, biaya kueri secara signifikan lebih rendah daripada yang menggunakan CTE rekursif, tetapi tidak serendah metode tambahan Lukasz Szozda.

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
Weihui Guo
sumber
2

Saya harap ini akan membantu Anda.

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
Abhijeet Khandagale
sumber
Terima kasih @ x00 untuk mengedit kode dalam format yang dapat dibaca, saya menggunakan ponsel saya untuk mengirim jawaban sehingga tidak dapat memberikan lekukan yang tepat.
Abhijeet Khandagale
Saya pikir ini pada dasarnya jawaban yang tepat. Tetapi ini adalah jawaban yang berkualitas buruk karena tidak dijelaskan dan kode memiliki kueri luar yang tidak perlu ketika modifikasi bagian dalam akan baik-baik saja. Jika Anda dapat menyelesaikan masalah-masalah itu, saya dengan senang hati akan memilih Anda.
pwilcox
1
@ pwilcox, terima kasih atas sarannya yang berharga, saya telah mengedit jawabannya dan mempostingnya sampai sekarang. Saat saya bepergian dan saya tidak membawa laptop, saya akan memposting penjelasan dalam satu atau dua hari.
Abhijeet Khandagale
1
@AbhijeetKhandagale Ini tidak sepenuhnya memenuhi persyaratan bisnis. Saya telah menambahkan skenario gagal dalam pertanyaan. Untuk pasien 303, janji tanggal 2 Februari harus Tindak Lanjut; tetapi permintaan Anda mengatakan itu "Baru"
LCJ
1

Anda bisa menggunakan Casepernyataan .

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

Pertanyaannya adalah, haruskah kategori ini ditetapkan berdasarkan penunjukan awal, atau yang sebelumnya? Yaitu, jika seorang Pasien telah memiliki tiga janji, haruskah kita membandingkan janji yang ketiga dengan yang pertama, atau yang kedua?

Masalah Anda nyatakan yang pertama, begitulah cara saya menjawab. Jika bukan itu masalahnya, Anda ingin menggunakannya lag.

Juga, perlu diingat bahwa DateDifftidak membuat pengecualian untuk akhir pekan. Jika ini hanya hari kerja, Anda harus membuat fungsi Scalar-Valued Anda sendiri.

pengguna
sumber
1
Ini tidak menautkan dua janji berurutan, ini menghubungkan appt 1 dengan semua janji berikut dan menghitung hari-antara untuk semuanya. Anda akan mengembalikan terlalu banyak rekaman dengan cara ini, karena appt 1 sekarang memiliki hubungan dengan 2, 3, 4, appt 2 memiliki hubungan dengan 3, 4 ...
steenbergh
Poin bagus. Saya memperbarui jawaban saya untuk melakukan subselect untuk A1.
pengguna
1
Itu tidak memberikan hasil yang diharapkan. Pengangkatan 20 Februari harus "Tindak Lanjut"
LCJ
Pertanyaannya tidak jelas ... Deskripsi posternya adalah ini: "Setiap perjanjian (untuk pasien) dalam waktu 30 hari sejak perjanjian pertama (dari pasien itu) adalah Tindak Lanjut. Setelah 30 hari, janji temu lagi" Baru ". Setiap janji temu 30 hari menjadi "Tindak Lanjut". " 5 Januari tentu saja lebih dari 30 hari dari 20 Februari, yaitu Baru. Namun, BUKAN 30 hari dari 12 Februari. Saya menawarkan solusi untuk apa yang ditulisnya, bukan tabel yang disediakan. Jika pengguna ingin menyelaraskan dengan apa yang disediakan tabel, mereka harus menggunakan lag. Mereka juga harus mengklarifikasi ...
pengguna
1

menggunakan fungsi Lag


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

Demo -> https://rextester.com/TNW43808

Digvijay S
sumber
2
Ini berfungsi pada data sampel saat ini tetapi mungkin menghasilkan hasil yang salah mengingat data sampel yang berbeda. Sekalipun Anda menggunakan apptDatesebagai order bykolom lagfungsi (yang sebenarnya harus Anda id bukan jaminan apa pun), itu masih bisa dengan mudah dipatahkan dengan memperkenalkan lebih banyak janji tindak lanjut. Lihat demo Rextester ini misalnya. Selamat mencoba, ...
Zohar Peled
Terima kasih. Seharusnya menggunakan tanggal alih-alih ID. Tetapi mengapa itu salah untuk apptID = 6 25.01.2020 - 12.02.2020 -> 18 hari -> tindak lanjut.
Digvijay S
2
Karena itu harus a Newdan bukan a FollowUp. Ini lebih dari 30 hari sejak penunjukan pertama pasien itu ... Anda harus menghitung 30 hari sejak setiap Newjanji dan kemudian menggunakan Newlagi ...
Zohar Peled
Iya. Terima kasih. :( Perlu membuat yang baru untuk memeriksa periode tanggal yang valid.
Digvijay S
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

Milik saya benar. Penulis salah, lihat sudah berlalu

Singa Emas
sumber