Query mit Datumsbereichen

haemi

Benutzer
Beiträge
6
Hallo,

Ich habe folgendes Szenario:

- eine Tabelle mit Patientendaten
- eine Tabelle Bewegungsdaten der Patienten

Auf Grundlage beider Tabellen sollte ich anhand des ersten Datumseintrages eines jeden Patienten in einem drei Monatszyklus Daten zusammenfassen können.

Beispiel:

Patient Name
4711 Meier
8810 Müller

Patient Datum Position Wert ID
8810 15.01.17 02.0200 35 1
8810 20.02.17 02.0200 50 2
8810 20.04.17 02.0200 20 3
4711 10.01.17 02.0200 15 4
4711 15.08.17 02.0200 55 5

Das Resultat sollte ungefähr so aussehen:

Patient Datumsbereich Wert
8810 15.01.17 - 14.04.17 85
8810 15.04.17 - 14.07.17 20
4711 10.01.17 - 09.04.17 15
4711 10.04.17 - 09.07.17 0
4711 10.07.17 - 09.10.17 55

Ich habe diverse Ansätze getestet (Cursor, Fetch...).

Hat hier jemand eine Idee?

Besten Dank im Voraus.
Hämi
 
Werbung:
Mal als Ansatz...

Code:
test=# select * from haemi ;
 patient |  datum  | position  | wert | id
---------+------------+-----------+------+----
  8810 | 2017-01-15 | '02.0200' |  35 |  1
  8810 | 2017-02-20 | '02.0200' |  50 |  2
  8810 | 2017-04-17 | '02.0200' |  20 |  3
  4711 | 2017-01-10 | '02.0200' |  15 |  4
  4711 | 2017-08-15 | '02.0200' |  55 |  5
(5 rows)

test=# with tmp as (select patient, min(datum), max(datum), extract(month from age(max(datum),min(datum)))::int / 3 + 1 as c
from haemi group by patient) select patient, min + (g-1) * '1month'::interval as start, min + g * '1month'::interval as ende from tmp left join lateral (select * from generate_series(1,tmp.c) g) x on (true);
 patient |  start  |  ende   
---------+---------------------+---------------------
  8810 | 2017-01-15 00:00:00 | 2017-02-15 00:00:00
  8810 | 2017-02-15 00:00:00 | 2017-03-15 00:00:00
  4711 | 2017-01-10 00:00:00 | 2017-02-10 00:00:00
  4711 | 2017-02-10 00:00:00 | 2017-03-10 00:00:00
  4711 | 2017-03-10 00:00:00 | 2017-04-10 00:00:00
(5 rows)

Erste Abfrage ist Deine Tabelle, die zweite Abfrage liefert jetzt schon mal die geforderten Zeitbereiche. Das kannst Du nun wieder mit der originalen Tabelle über die Zeitbereiche joinen, um daraus dann Deine gewünschte Aggregation zu machen.

Ich mache da jetzt nicht weiter, weil ich PostgreSQL nutze und viele der Features in anderen Datenbanken wie wohl auch in Deiner nicht zur Verfügung stehen.

Wenn ich weitermachen würde, würde ich start und ende erst einmal zu einer DATERANGE verbinden, macht den Rest dann einfacher. Ich hoffe, der Weg ist halbwegs verständlich, aber Dinge wie genertae_series() und wohl erst besonders den LATERAL JOIN wirst Du nicht haben. DATERANGE auch nicht.
 
ich seh grad, ich hab dann bei der Ausgabe mit 1 Monat gearbeitet, korrekt wäre gewesen:

Code:
test=# with tmp as (select patient, min(datum), max(datum), extract(month from age(max(datum),min(datum)))::int / 3 + 1 as c
from haemi group by patient) select patient, min + (g-1) * '3month'::interval as start, min + g * '3month'::interval as ende from tmp left join lateral (select * from generate_series(1,tmp.c) g) x on (true);
 patient |  start  |  ende   
---------+---------------------+---------------------
  8810 | 2017-01-15 00:00:00 | 2017-04-15 00:00:00
  8810 | 2017-04-15 00:00:00 | 2017-07-15 00:00:00
  4711 | 2017-01-10 00:00:00 | 2017-04-10 00:00:00
  4711 | 2017-04-10 00:00:00 | 2017-07-10 00:00:00
  4711 | 2017-07-10 00:00:00 | 2017-10-10 00:00:00
(5 rows)

test=#
 
Hallo

Vielen Dank für die rasche Antwort. Ich benutze MS SQL 2014 .

Dein Ansatz tönt interessant - nur leider habe ich keine "generate_series" in MS SQL.

Mein Ansatz sieht folgendermassen aus:

USE
VWORK

TRUNCATE Table PatCockpit

DECLARE
@BL_PATNR int,
@vStartDate date,
@vEndDate date=getDate(),
@vFinishDate date,
@vSumZeitReal smallint

DECLARE C CURSOR FOR SELECT DISTINCT BL_PATNR
FROM VMW
WHERE BL_POSNR='02.0200'
ORDER BY BL_PATNR
OPEN C

FETCH NEXT FROM C INTO @BL_PATNR

WHILE @@FETCH_STATUS= 0 BEGIN
-- Search first entry
SELECT TOP 1
@vStartDate=BL_DATUM
FROM VMW
WHERE BL_POSNR = '02.0200' and BL_PATNR = @BL_PATNR
GROUP BY BL_DATUM

-- Date range and calculation
WHILE @vStartDate < Dateadd(month,+3,@vEndDate)
BEGIN
SET @vFinishDate = Dateadd(month,+3,@vStartDate)
SELECT
@vSumZeitReal = SUM(BL_ZEITREAL)
FROM VMW
WHERE BL_POSNR = '02.0200' and BL_PATNR=@BL_PATNR and BL_DATUM BETWEEN @vStartDate and @vFinishDate
IF @vSumZeitReal is not NULL
INSERT INTO PatCockpit (PatNr,StartDate,EndDate,TimeReal,ServiceGroup) VALUES(@BL_PATNR,@vStartDate,@vFinishDate,@vSumZeitReal,9)

SET @vStartDate = Dateadd(month,+3,@vStartDate)
END
FETCH NEXT FROM C INTO @BL_PATNR
END

CLOSE C
DEALLOCATE C

Dies läuft soweit. Bei der grossen Datenmenge (>25'000 Patienten bzw. > 10 Mio. Bewegungsdaten) ist die Abfrage einfach zu langsam.

Andere Ideen?

Danke.
 
Hallo

Vielen Dank für die rasche Antwort. Ich benutze MS SQL 2014 .

Dein Ansatz tönt interessant - nur leider habe ich keine "generate_series" in MS SQL.

...

Dies läuft soweit. Bei der grossen Datenmenge (>25'000 Patienten bzw. > 10 Mio. Bewegungsdaten) ist die Abfrage einfach zu langsam.

Andere Ideen?

Danke.


*shrug*

DB wechseln?

Wie Du siehst, kann PG solche Dinge ohne großes rumgemache mit vielen Schleifen und so in einem Einzeiler handeln. Und mal ehrlich: 10 Millionen Rows ist ja eher peanuts. Unsere Kunden, die "große" Datenmengen haben, haben teilweise 2-stellige Milliarden von Rows pro Table.
 
DB wechseln wäre gut ;). Dürfen aber "nur" MS SQL benutzen.

Zu den Datenmengen
Ja sind nur Peanuts. Die Positionstabelle habe ich in meiner Abfrage noch nicht drin (im Beispiel 02.0200). Sind ebenfalls über 1'000 Einträge. In Relation Patienten, Positionen und Bewegungsdaten wird dies eine "grössere" Matrix ergeben. Hinzu kommt noch, dass bei den Positionen Zeit- und Wertlimiten bestehen. Diese werden schlussendlich auch berücksichtigt.

Übrigens: Das Gesamte läuft auf ein Patienten Cockpit hin.

Danke.
 
Werbung:
Kenne mich mit Access überhaupt nicht aus, sollte aber mittels Excel (was du ja angeblich nutzen darfst, da ein Office-Programm), einfach über Tabellenübergreifende "Verknüpfungen" machbar sein.
 
Zurück
Oben