Query ricorsiva di SQL Server
-
26-09-2019 - |
Domanda
Alcuni giorni fa ho posto una domanda su SO riguardo aiuto su una query ricorsiva.
Il problema di quella domanda era "Come ottenere la cronologia degli appuntamenti di una persona".
Ora sto riscontrando un problema simile a quello ma dovrebbe rispondere a una domanda leggermente diversa:
How to get an Appointment history?
Ad esempio se l'Appuntamento con ID=5 è stato posticipato una volta e si trattava del rinvio di un altro appuntamento come ottengo il seguente risultato?
AppointmentID PrevAppointmentID
----------------- ----------------------
1 NULL
5 1
12 5
Grazie dell'aiuto
Aggiornamento:
Questi script ti aiuteranno a creare la tabella per le tue prove
CREATE TABLE [dbo].[Appointments](
[AppointmentID] [int] IDENTITY(1,1) NOT NULL,
[IssueID] [int] NOT NULL,
[Location] [varchar](255) NOT NULL,
[Description] [varchar](255) NOT NULL,
[AppointmentDate] [datetime] NOT NULL,
[AppointmentHour] [datetime] NOT NULL,
[Done] [bit] NOT NULL,
[PrevAppointmentID] [int] NULL,
CONSTRAINT [PK_Appointments] PRIMARY KEY CLUSTERED
(
[AppointmentID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Soluzione
Non ho voglia di dirottare completamente la sua risposta, così:
Utilizzo di risposta di Brad
Questa è la query per ottenere la storia completa:
WITH cte
AS ( SELECT AppointmentId ,
PrevAppointmentId
FROM Appointments
WHERE AppointmentId = @AppointmentId
UNION ALL
SELECT prev.AppointmentId ,
prev.PrevAppointmentId
FROM Appointments prev
INNER JOIN cte curr ON prev.AppointmentId = curr.PrevAppointmentId
),
cte1
AS ( SELECT AppointmentId ,
PrevAppointmentId
FROM Appointments
WHERE AppointmentId = @AppointmentId
UNION ALL
SELECT prev.AppointmentId ,
prev.PrevAppointmentId
FROM Appointments prev
INNER JOIN cte1 curr ON prev.PrevAppointmentId = curr.AppointmentId
)
SELECT *
FROM cte
UNION
SELECT *
FROM cte1
Altri suggerimenti
Logic:
- Ottenere la nomina in questione
- Ricorre unirsi alla applicazione padre
- Seleziona tutti i risultati
Domanda:
DECLARE @appointmentId INT
SET @appointmentId = 3
--
;
WITH past
AS ( SELECT AppointmentId ,
PrevAppointmentId
FROM Appointments
WHERE AppointmentId = @AppointmentId
UNION ALL
SELECT prev.AppointmentId ,
prev.PrevAppointmentId
FROM Appointments prev
INNER JOIN cte curr ON prev.AppointmentId = curr.PrevAppointmentId
),
future
AS ( SELECT AppointmentId ,
PrevAppointmentId
FROM Appointments
WHERE AppointmentId = @AppointmentId
UNION ALL
SELECT prev.AppointmentId ,
prev.PrevAppointmentId
FROM Appointments prev
INNER JOIN cte1 curr ON prev.PrevAppointmentId = curr.AppointmentId
)
SELECT *
FROM past OPTION(MAXRECURSION 500)
UNION
SELECT *
FROM future OPTION(MAXRECURSION 500)
In risposta ad una domanda dell'OP:
Incontri efficaci
La datazione effettiva è quando aggiungi a DateTime
colonna alla tabella che controlla quando il record diventa "effettivo".La colonna viene quindi aggiunta al file PK
della tabella che rende ciascuna voce una registrazione di ciò che era "in vigore" in un dato momento (la data di entrata in vigore).Con gli appuntamenti efficaci, mai DELETE
O UPDATE
, soltanto INSERT
il che significa che hai sempre un completare storia dell'oggetto nel tempo.
Per trovare il record più efficace, seleziona la riga con l'efficacia massima che non sia futura
SELECT *
FROM Appointments a1
WHERE EffectiveDate = (SELECT MAX(EffectiveDate)
FROM Appointments a2
WHERE a1.AppointmentId = a2.AppointmentId
AND a2.EffectiveDate <= ISNULL(@asOfDate, GETDATE()
)
Ciò significa che puoi anche tu pre-data record.Ad esempio, oggi ti viene approvato un aumento di stipendio, ma non entrerà in vigore prima di 2 settimane.
Quindi, per trovare la cronologia di un appuntamento, basterebbe semplicemente:
SELECT *
FROM Appointments
WHERE AppointmentId = @appointmentId
ORDER BY EffectiveDate