16 Commits

Author SHA1 Message Date
4c8c6295e0 chore: bump version 2024-05-23 08:29:49 +02:00
9f5188ce5d feat: use PathBuf as argument type 2024-05-23 08:27:24 +02:00
af44351f09 feat: enable messages with 'histologie_zytologie' using optional flag 2024-05-22 16:09:45 +02:00
02497cd007 refactor: replace deprecated method 2024-05-22 10:39:53 +02:00
9d7e511725 chore: bump version 2024-05-22 10:27:35 +02:00
e4c3e61f35 chore: update dependencies 2024-05-22 10:26:56 +02:00
38f9fe3628 chore: code cleanup 2024-05-22 10:26:35 +02:00
ab15e5c9ff feat: ignore messages containing 'histologie_zytologie' 2024-05-21 16:11:54 +02:00
8ec24efc96 chore: bump version 2024-05-16 17:33:28 +02:00
180d808dd4 fix: include older exported versions instead of skipping 2024-05-16 17:32:59 +02:00
ba97610fbe chore: bump version 2024-05-16 12:41:59 +02:00
655995070c feat: do not include external diagnoses by default 2024-05-16 12:33:53 +02:00
4cf671716f docs: add information about csv export option 2024-04-04 08:10:07 +02:00
3684ff8172 feat: add export with semicolon as separator 2024-04-03 19:47:30 +02:00
c4c2297bb0 docs: add information about supported databases. 2024-04-03 14:37:41 +02:00
9a87aa5e97 chore: update dependencies 2024-03-27 14:46:11 +01:00
8 changed files with 143 additions and 48 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "bzkf-rwdp-check" name = "bzkf-rwdp-check"
version = "0.2.0" version = "0.3.3"
edition = "2021" edition = "2021"
authors = ["Paul-Christian Volkmer <volkmer_p@ukw.de>"] authors = ["Paul-Christian Volkmer <volkmer_p@ukw.de>"]
description = "Anwendung zur Durchführung einer Plausibilitätsprüfung anhand der Daten für die BZKF Real World Data Platform." description = "Anwendung zur Durchführung einer Plausibilitätsprüfung anhand der Daten für die BZKF Real World Data Platform."
@ -11,8 +11,8 @@ clap = { version = "4.5", features = ["std", "help", "usage", "derive", "error-c
console = "0.15" console = "0.15"
csv = "1.3" csv = "1.3"
dialoguer = "0.11" dialoguer = "0.11"
itertools = "0.12" itertools = "0.13"
mysql = "24.0" mysql = "25.0"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
urlencoding = "2.1" urlencoding = "2.1"
regex = "1.10" regex = "1.10"

View File

@ -22,6 +22,9 @@ flowchart LR
Die Anwendung gibt für die möglichen Quellen der Kennzahlen die Anzahl der _Conditions_, gruppiert nach ICD-10 Gruppen, Die Anwendung gibt für die möglichen Quellen der Kennzahlen die Anzahl der _Conditions_, gruppiert nach ICD-10 Gruppen,
aus. aus.
Unterstützt wird eien OPAL-CSV-Datei (wie für BZKF vorgesehen) und eine Onkostar-Datenbank, basierend auf MariaDB oder
MySQL.
![Ausgabe](docs/screenshot.png) ![Ausgabe](docs/screenshot.png)
## Kennzahlen aus der CSV-Datei ## Kennzahlen aus der CSV-Datei
@ -37,8 +40,8 @@ Die Anwendung gibt nun eine Liste der ICD-10-Gruppen mit Anzahl der _Conditions_
## Kennzahlen aus der Onkostar-Datenbank ## Kennzahlen aus der Onkostar-Datenbank
Die Anzahl der _Conditions_, gruppiert nach ICD-10-Gruppe, kann auch mit dem Befehl `database` aus der Onkostar-Datenbank Die Anzahl der _Conditions_, gruppiert nach ICD-10-Gruppe, kann auch mit dem Befehl `database` aus der
abgerufen werden. Onkostar-Datenbank abgerufen werden.
``` ```
bzkf-rwdp-check database --user me --year 2024 bzkf-rwdp-check database --user me --year 2024
@ -62,6 +65,12 @@ Der zusätzliche Parameter `--ignore-exports-since` ist optional.
Wird er angegeben, werden keine Einträge mit Exportdatum ab diesem Datum verwendet. Wird er angegeben, werden keine Einträge mit Exportdatum ab diesem Datum verwendet.
Dies eignet sich um nachträglich Zahlen zu einem bestimmten Datum zu ermitteln. Dies eignet sich um nachträglich Zahlen zu einem bestimmten Datum zu ermitteln.
Der optionale Parameter `--include-extern` schließt Meldungen mit externer Diagnosestellung ein.
Diese sind normalerweise nicht enthalten.
Der optionale Parameter `--include-histo-zyto` schließt Meldungen mit Meldeanlass `histologhie_zytologie` ein.
Diese sind normalerweise ebenfalls nicht enthalten.
## Export aus der Onkostar-Datenbank ## Export aus der Onkostar-Datenbank
Die Anwendung ist in der Lage, mit dem Befehl `export` die Spalten Die Anwendung ist in der Lage, mit dem Befehl `export` die Spalten
@ -73,18 +82,20 @@ Die Anwendung ist in der Lage, mit dem Befehl `export` die Spalten
in eine CSV-Datei zum Abgleich mit der OPAL-CSV-Datei zu exportieren. in eine CSV-Datei zum Abgleich mit der OPAL-CSV-Datei zu exportieren.
Hierbei gelten die gleichen Datenbank-Parameter wie unter [Kennzahlen aus der Onkostar-Datenbank](#kennzahlen-aus-der-onkostar-datenbank), Hierbei gelten die gleichen Datenbank-Parameter wie
zusätzlich gibt es noch die folgenden Parameter: unter [Kennzahlen aus der Onkostar-Datenbank](#kennzahlen-aus-der-onkostar-datenbank), zusätzlich gibt es noch die
folgenden Parameter:
``` ```
Options: Options:
--pat-id Export mit Klartext-Patienten-ID --pat-id Export mit Klartext-Patienten-ID
-o, --output <OUTPUT> Ausgabedatei -o, --output <OUTPUT> Ausgabedatei
--xls-csv Export mit Trennzeichen ';' für Excel
``` ```
## Vergleich CSV-Datei für OPAL und Onkostar-Datenbank ## Vergleich CSV-Datei für OPAL und Onkostar-Datenbank
Die Anwendung kann auch die Conditions in der CSV-Datei mit der Onkostar-Datenbank direkt vergleichen. Die Anwendung kann auch die Conditions in der CSV-Datei mit der Onkostar-Datenbank direkt vergleichen.
Hierzu kann der Befehl `compare` genutzt werden. Dieser verwendet alle Optionen für die Datenbank und die Option `--file` Hierzu kann der Befehl `compare` genutzt werden. Dieser verwendet alle Optionen für die Datenbank und die
für die CSV-Datei und gibt eine Übersicht auf der Konsole aus. Option `--file` für die CSV-Datei und gibt eine Übersicht auf der Konsole aus.

View File

@ -20,6 +20,7 @@
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use regex::Regex; use regex::Regex;
use std::path::PathBuf;
#[derive(Parser)] #[derive(Parser)]
#[command(author, version, about)] #[command(author, version, about)]
@ -34,7 +35,7 @@ pub enum SubCommand {
#[command(about = "Ermittelt die Prüfwerte aus einem CSV-File für OPAL")] #[command(about = "Ermittelt die Prüfwerte aus einem CSV-File für OPAL")]
OpalFile { OpalFile {
#[arg(short, long, help = "CSV-File für Opal")] #[arg(short, long, help = "CSV-File für Opal")]
file: String, file: PathBuf,
}, },
#[command(about = "Ermittelt die Prüfwerte aus der Onkostar-Datenbank")] #[command(about = "Ermittelt die Prüfwerte aus der Onkostar-Datenbank")]
Database { Database {
@ -61,6 +62,13 @@ pub enum SubCommand {
year: String, year: String,
#[arg(long, value_parser = value_is_date, help = "Ignoriere LKR-Exporte seit Datum")] #[arg(long, value_parser = value_is_date, help = "Ignoriere LKR-Exporte seit Datum")]
ignore_exports_since: Option<String>, ignore_exports_since: Option<String>,
#[arg(long, help = "Meldungen mit externer Diagnose einschließen")]
include_extern: bool,
#[arg(
long,
help = "Meldungen mit Meldeanlass 'histologie_zytologie' einschließen"
)]
include_histo_zyto: bool,
}, },
#[command( #[command(
about = "Erstellt eine (reduzierte) CSV-Datei zum direkten Vergleich mit der OPAL-CSV-Datei" about = "Erstellt eine (reduzierte) CSV-Datei zum direkten Vergleich mit der OPAL-CSV-Datei"
@ -88,11 +96,20 @@ pub enum SubCommand {
#[arg(short = 'u', long, help = "Benutzername")] #[arg(short = 'u', long, help = "Benutzername")]
user: String, user: String,
#[arg(short = 'o', long, help = "Ausgabedatei")] #[arg(short = 'o', long, help = "Ausgabedatei")]
output: String, output: PathBuf,
#[arg(short = 'y', long, help = "Jahr der Diagnose")] #[arg(short = 'y', long, help = "Jahr der Diagnose")]
year: String, year: String,
#[arg(long, value_parser = value_is_date, help = "Ignoriere LKR-Exporte seit Datum")] #[arg(long, value_parser = value_is_date, help = "Ignoriere LKR-Exporte seit Datum")]
ignore_exports_since: Option<String>, ignore_exports_since: Option<String>,
#[arg(long, help = "Export mit Trennzeichen ';' für Excel")]
xls_csv: bool,
#[arg(long, help = "Meldungen mit externer Diagnose einschließen")]
include_extern: bool,
#[arg(
long,
help = "Meldungen mit Meldeanlass 'histologie_zytologie' einschließen"
)]
include_histo_zyto: bool,
}, },
#[command(about = "Abgleich zwischen CSV-Datei für OPAL und Onkostar-Datenbank")] #[command(about = "Abgleich zwischen CSV-Datei für OPAL und Onkostar-Datenbank")]
Compare { Compare {
@ -118,11 +135,18 @@ pub enum SubCommand {
#[arg(short = 'u', long, help = "Benutzername")] #[arg(short = 'u', long, help = "Benutzername")]
user: String, user: String,
#[arg(short, long, help = "CSV-File für Opal")] #[arg(short, long, help = "CSV-File für Opal")]
file: String, file: PathBuf,
#[arg(short = 'y', long, help = "Jahr der Diagnose")] #[arg(short = 'y', long, help = "Jahr der Diagnose")]
year: String, year: String,
#[arg(long, value_parser = value_is_date, help = "Ignoriere LKR-Exporte seit Datum")] #[arg(long, value_parser = value_is_date, help = "Ignoriere LKR-Exporte seit Datum")]
ignore_exports_since: Option<String>, ignore_exports_since: Option<String>,
#[arg(long, help = "Meldungen mit externer Diagnose einschließen")]
include_extern: bool,
#[arg(
long,
help = "Meldungen mit Meldeanlass 'histologie_zytologie' einschließen"
)]
include_histo_zyto: bool,
}, },
} }

View File

@ -63,7 +63,7 @@ impl Check {
icd10_code: Self::map_icd_code(&record.icd10_code), icd10_code: Self::map_icd_code(&record.icd10_code),
}) })
.sorted_by_key(|record| record.icd10_code.to_string()) .sorted_by_key(|record| record.icd10_code.to_string())
.group_by(|record| record.icd10_code.to_string()) .chunk_by(|record| record.icd10_code.to_string())
.into_iter() .into_iter()
.map(|(icd10, group)| (icd10, group.collect::<Vec<_>>())) .map(|(icd10, group)| (icd10, group.collect::<Vec<_>>()))
.map(|record| Icd10GroupSize { .map(|record| Icd10GroupSize {

View File

@ -18,9 +18,10 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
use std::time::Duration;
use mysql::prelude::Queryable; use mysql::prelude::Queryable;
use mysql::{params, Pool}; use mysql::{params, Pool};
use std::time::Duration;
use crate::common::{ExportData, Icd10GroupSize}; use crate::common::{ExportData, Icd10GroupSize};
use crate::resources::{EXPORT_QUERY, SQL_QUERY}; use crate::resources::{EXPORT_QUERY, SQL_QUERY};
@ -34,13 +35,24 @@ impl DatabaseSource {
DatabaseSource(url) DatabaseSource(url)
} }
pub fn check(&self, year: &str, ignore_exports_since: &str) -> Result<Vec<Icd10GroupSize>, ()> { pub fn check(
&self,
year: &str,
ignore_exports_since: &str,
include_extern: bool,
include_histo_zyto: bool,
) -> Result<Vec<Icd10GroupSize>, ()> {
match Pool::new(self.0.as_str()) { match Pool::new(self.0.as_str()) {
Ok(pool) => { Ok(pool) => {
if let Ok(mut connection) = pool.try_get_conn(Duration::from_secs(3)) { if let Ok(mut connection) = pool.try_get_conn(Duration::from_secs(3)) {
return match connection.exec_map( return match connection.exec_map(
SQL_QUERY, SQL_QUERY,
params! {"year" => year, "ignore_exports_since" => ignore_exports_since}, params! {
"year" => year,
"ignore_exports_since" => ignore_exports_since,
"include_extern" => if include_extern { 1 } else { 0 },
"include_histo_zyto" => if include_histo_zyto { 1 } else { 0 }
},
|(icd10_group, count)| Icd10GroupSize { |(icd10_group, count)| Icd10GroupSize {
name: icd10_group, name: icd10_group,
size: count, size: count,
@ -64,13 +76,20 @@ impl DatabaseSource {
year: &str, year: &str,
ignore_exports_since: &str, ignore_exports_since: &str,
use_pat_id: bool, use_pat_id: bool,
include_extern: bool,
include_histo_zyto: bool,
) -> Result<Vec<ExportData>, ()> { ) -> Result<Vec<ExportData>, ()> {
match Pool::new(self.0.as_str()) { match Pool::new(self.0.as_str()) {
Ok(pool) => { Ok(pool) => {
if let Ok(mut connection) = pool.try_get_conn(Duration::from_secs(3)) { if let Ok(mut connection) = pool.try_get_conn(Duration::from_secs(3)) {
return match connection.exec_map( return match connection.exec_map(
EXPORT_QUERY, EXPORT_QUERY,
params! {"year" => year, "ignore_exports_since" => ignore_exports_since}, params! {
"year" => year,
"ignore_exports_since" => ignore_exports_since,
"include_extern" => if include_extern { 1 } else { 0 },
"include_histo_zyto" => if include_histo_zyto { 1 } else { 0 }
},
|(condition_id, icd_10_code, diagnosis_date, pat_id)| ExportData { |(condition_id, icd_10_code, diagnosis_date, pat_id)| ExportData {
condition_id, condition_id,
icd_10_code, icd_10_code,

View File

@ -19,11 +19,10 @@
*/ */
use std::error::Error; use std::error::Error;
use std::path::Path;
use clap::Parser; use clap::Parser;
use console::{style, Term}; use console::{style, Term};
use csv::Writer; use csv::WriterBuilder;
use itertools::Itertools; use itertools::Itertools;
use crate::cli::{Cli, SubCommand}; use crate::cli::{Cli, SubCommand};
@ -87,13 +86,27 @@ fn print_items(items: &[Icd10GroupSize]) {
let _ = term.write_line(&style("".repeat(27)).dim().to_string()); let _ = term.write_line(&style("".repeat(27)).dim().to_string());
} }
fn print_extern_notice(include_extern: bool) {
let _ = Term::stdout().write_line(
format!(
"{} Die Datenbankanfrage schließt Meldungen mit externer Diagnose {}.",
style("Hinweis:").bold().underlined(),
match include_extern {
true => style("ein").yellow(),
false => style("nicht ein (Standard)").green(),
}
)
.as_str(),
);
}
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
let term = Term::stdout(); let term = Term::stdout();
match Cli::parse().cmd { match Cli::parse().cmd {
SubCommand::OpalFile { file } => { SubCommand::OpalFile { file } => {
let items = opal::OpalCsvFile::check(Path::new(&file)) let items =
.map_err(|_e| "Kann Datei nicht lesen")?; opal::OpalCsvFile::check(file.as_path()).map_err(|_e| "Kann Datei nicht lesen")?;
print_items(&items); print_items(&items);
} }
@ -105,6 +118,8 @@ fn main() -> Result<(), Box<dyn Error>> {
user, user,
year, year,
ignore_exports_since, ignore_exports_since,
include_extern,
include_histo_zyto,
} => { } => {
let password = request_password_if_none(password); let password = request_password_if_none(password);
let year = sanitize_year(year); let year = sanitize_year(year);
@ -117,11 +132,17 @@ fn main() -> Result<(), Box<dyn Error>> {
let db = DatabaseSource::new(&database, &host, &password, port, &user); let db = DatabaseSource::new(&database, &host, &password, port, &user);
let items = db let items = db
.check(&year, &ignore_exports_since.unwrap_or("9999-12-31".into())) .check(
&year,
&ignore_exports_since.unwrap_or("9999-12-31".into()),
include_extern,
include_histo_zyto,
)
.map_err(|_e| "Fehler bei Zugriff auf die Datenbank")?; .map_err(|_e| "Fehler bei Zugriff auf die Datenbank")?;
let _ = term.clear_last_lines(1); let _ = term.clear_last_lines(1);
print_extern_notice(include_extern);
print_items(&items); print_items(&items);
} }
SubCommand::Export { SubCommand::Export {
@ -134,6 +155,9 @@ fn main() -> Result<(), Box<dyn Error>> {
output, output,
year, year,
ignore_exports_since, ignore_exports_since,
xls_csv,
include_extern,
include_histo_zyto,
} => { } => {
let password = request_password_if_none(password); let password = request_password_if_none(password);
let year = sanitize_year(year); let year = sanitize_year(year);
@ -150,12 +174,21 @@ fn main() -> Result<(), Box<dyn Error>> {
&year, &year,
&ignore_exports_since.unwrap_or("9999-12-31".into()), &ignore_exports_since.unwrap_or("9999-12-31".into()),
pat_id, pat_id,
include_extern,
include_histo_zyto,
) )
.map_err(|_e| "Fehler bei Zugriff auf die Datenbank")?; .map_err(|_e| "Fehler bei Zugriff auf die Datenbank")?;
let _ = term.clear_last_lines(1); let _ = term.clear_last_lines(1);
let mut writer = Writer::from_path(Path::new(&output)).expect("writeable file"); let writer_builder = &mut WriterBuilder::new();
let mut writer_builder = writer_builder.has_headers(true);
if xls_csv {
writer_builder = writer_builder.delimiter(b';');
}
let mut writer = writer_builder
.from_path(output.as_path())
.expect("writeable file");
items items
.iter() .iter()
@ -166,11 +199,13 @@ fn main() -> Result<(), Box<dyn Error>> {
"{} Conditions für das Jahr {} in Datei '{}' exportiert", "{} Conditions für das Jahr {} in Datei '{}' exportiert",
items.len(), items.len(),
year, year,
output output.to_str().unwrap_or_default()
)) ))
.green() .green()
.to_string(), .to_string(),
); );
print_extern_notice(include_extern);
} }
SubCommand::Compare { SubCommand::Compare {
pat_id, pat_id,
@ -182,6 +217,8 @@ fn main() -> Result<(), Box<dyn Error>> {
file, file,
year, year,
ignore_exports_since, ignore_exports_since,
include_extern,
include_histo_zyto,
} => { } => {
let password = request_password_if_none(password); let password = request_password_if_none(password);
let year = sanitize_year(year); let year = sanitize_year(year);
@ -198,13 +235,15 @@ fn main() -> Result<(), Box<dyn Error>> {
&year, &year,
&ignore_exports_since.unwrap_or("9999-12-31".into()), &ignore_exports_since.unwrap_or("9999-12-31".into()),
pat_id, pat_id,
include_extern,
include_histo_zyto,
) )
.map_err(|_e| "Fehler bei Zugriff auf die Datenbank")?; .map_err(|_e| "Fehler bei Zugriff auf die Datenbank")?;
let _ = term.clear_last_lines(1); let _ = term.clear_last_lines(1);
let csv_items = opal::OpalCsvFile::export(Path::new(&file)) let csv_items =
.map_err(|_e| "Kann Datei nicht lesen")?; opal::OpalCsvFile::export(file.as_path()).map_err(|_e| "Kann Datei nicht lesen")?;
let mut not_in_csv = db_items let mut not_in_csv = db_items
.iter() .iter()
@ -216,12 +255,14 @@ fn main() -> Result<(), Box<dyn Error>> {
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
print_extern_notice(include_extern);
let _ = term.write_line( let _ = term.write_line(
&style(format!( &style(format!(
"{} Conditions aus der Datenbank für das Jahr {} - aber nicht in Datei '{}'", "{} Conditions aus der Datenbank für das Jahr {} - aber nicht in Datei '{}'",
not_in_csv.len(), not_in_csv.len(),
year, year,
file file.to_str().unwrap_or_default()
)) ))
.green() .green()
.to_string(), .to_string(),
@ -279,7 +320,7 @@ fn main() -> Result<(), Box<dyn Error>> {
&style(format!( &style(format!(
"{} Conditions aus Datei '{}' - aber nicht in der Datenbank für das Jahr {}", "{} Conditions aus Datei '{}' - aber nicht in der Datenbank für das Jahr {}",
not_in_db.len(), not_in_db.len(),
file, file.to_str().unwrap_or_default(),
year year
)) ))
.green() .green()

View File

@ -29,23 +29,23 @@ FROM (
EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID') AS pid, EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID') AS pid,
lme.versionsnummer, lme.versionsnummer,
SHA2(CONCAT('https://fhir.diz.uk-erlangen.de/identifiers/onkostar-xml-condition-id|', EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID'), 'condition', EXTRACTVALUE(lme.xml_daten, '//Diagnose/@Tumor_ID')), 256) AS cond_id, SHA2(CONCAT('https://fhir.diz.uk-erlangen.de/identifiers/onkostar-xml-condition-id|', EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID'), 'condition', EXTRACTVALUE(lme.xml_daten, '//Diagnose/@Tumor_ID')), 256) AS cond_id,
SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Primaertumor_ICD_Code'), ' ', 1) AS condcodingcode, SUBSTRING_INDEX(EXTRACTVALUE(lm.xml_daten, '//Primaertumor_ICD_Code'), ' ', 1) AS condcodingcode,
SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1) AS diagnosedatum, SUBSTRING_INDEX(EXTRACTVALUE(lm.xml_daten, '//Diagnosedatum'), ' ', 1) AS diagnosedatum,
SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) AS diagnosejahr SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lm.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) AS diagnosejahr
FROM lkr_meldung_export lme FROM lkr_meldung_export lme
JOIN lkr_meldung lm ON (lm.id = lme.lkr_meldung AND lme.typ <> '-1') JOIN lkr_meldung lm ON (lm.id = lme.lkr_meldung AND lme.typ <> '-1' AND lm.extern <= :include_extern)
JOIN lkr_export le ON (le.id = lme.lkr_export) WHERE lm.xml_daten LIKE '%ICD_Version%'
WHERE lme.xml_daten LIKE '%ICD_Version%' AND SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lm.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) = :year
AND SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) = :year AND (lm.xml_daten LIKE '%<cTNM%' OR lm.xml_daten LIKE '%<pTNM%' OR lm.xml_daten LIKE '%<Menge_Histologie>%' OR lm.xml_daten LIKE '%<Menge_Weitere_Klassifikation>%')
AND (lme.xml_daten LIKE '%<cTNM%' OR lme.xml_daten LIKE '%<pTNM%' OR lme.xml_daten LIKE '%<Menge_Histologie>%' OR lme.xml_daten LIKE '%<Menge_Weitere_Klassifikation>%') AND (lm.xml_daten NOT LIKE '%histologie_zytologie%' OR 1 = :include_histo_zyto)
AND le.exportiert_am < :ignore_exports_since
) o1 ) o1
LEFT OUTER JOIN ( LEFT OUTER JOIN (
SELECT SELECT DISTINCT
SHA2(CONCAT('https://fhir.diz.uk-erlangen.de/identifiers/onkostar-xml-condition-id|', EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID'), 'condition', EXTRACTVALUE(lme.xml_daten, '//Diagnose/@Tumor_ID')), 256) AS cond_id, SHA2(CONCAT('https://fhir.diz.uk-erlangen.de/identifiers/onkostar-xml-condition-id|', EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID'), 'condition', EXTRACTVALUE(lme.xml_daten, '//Diagnose/@Tumor_ID')), 256) AS cond_id,
MAX(versionsnummer) AS max_version CASE WHEN le.exportiert_am < :ignore_exports_since THEN MAX(versionsnummer) ELSE ~0 END AS max_version
FROM lkr_meldung_export lme FROM lkr_meldung_export lme
JOIN lkr_export le ON (lme.lkr_export = le.id)
WHERE SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) = :year WHERE SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) = :year
GROUP BY cond_id ORDER BY cond_id GROUP BY cond_id ORDER BY cond_id

View File

@ -115,22 +115,22 @@ FROM (
EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID') AS pid, EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID') AS pid,
lme.versionsnummer, lme.versionsnummer,
SHA2(CONCAT('https://fhir.diz.uk-erlangen.de/identifiers/onkostar-xml-condition-id|', EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID'), 'condition', EXTRACTVALUE(lme.xml_daten, '//Diagnose/@Tumor_ID')), 256) AS cond_id, SHA2(CONCAT('https://fhir.diz.uk-erlangen.de/identifiers/onkostar-xml-condition-id|', EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID'), 'condition', EXTRACTVALUE(lme.xml_daten, '//Diagnose/@Tumor_ID')), 256) AS cond_id,
SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Primaertumor_ICD_Code'), ' ', 1) AS condcodingcode, SUBSTRING_INDEX(EXTRACTVALUE(lm.xml_daten, '//Primaertumor_ICD_Code'), ' ', 1) AS condcodingcode,
SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) AS diagnosejahr SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lm.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) AS diagnosejahr
FROM lkr_meldung_export lme FROM lkr_meldung_export lme
JOIN lkr_meldung lm ON (lm.id = lme.lkr_meldung AND lme.typ <> '-1') JOIN lkr_meldung lm ON (lm.id = lme.lkr_meldung AND lme.typ <> '-1' AND lm.extern <= :include_extern)
JOIN lkr_export le ON (le.id = lme.lkr_export)
WHERE lme.xml_daten LIKE '%ICD_Version%' WHERE lme.xml_daten LIKE '%ICD_Version%'
AND SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) = :year AND SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lm.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) = :year
AND (lme.xml_daten LIKE '%<cTNM%' OR lme.xml_daten LIKE '%<pTNM%' OR lme.xml_daten LIKE '%<Menge_Histologie>%' OR lme.xml_daten LIKE '%<Menge_Weitere_Klassifikation>%') AND (lm.xml_daten LIKE '%<cTNM%' OR lm.xml_daten LIKE '%<pTNM%' OR lm.xml_daten LIKE '%<Menge_Histologie>%' OR lm.xml_daten LIKE '%<Menge_Weitere_Klassifikation>%')
AND le.exportiert_am < :ignore_exports_since AND (lm.xml_daten NOT LIKE '%histologie_zytologie%' OR 1 = :include_histo_zyto)
) o1 ) o1
LEFT OUTER JOIN ( LEFT OUTER JOIN (
SELECT SELECT DISTINCT
SHA2(CONCAT('https://fhir.diz.uk-erlangen.de/identifiers/onkostar-xml-condition-id|', EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID'), 'condition', EXTRACTVALUE(lme.xml_daten, '//Diagnose/@Tumor_ID')), 256) AS cond_id, SHA2(CONCAT('https://fhir.diz.uk-erlangen.de/identifiers/onkostar-xml-condition-id|', EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID'), 'condition', EXTRACTVALUE(lme.xml_daten, '//Diagnose/@Tumor_ID')), 256) AS cond_id,
MAX(versionsnummer) AS max_version CASE WHEN le.exportiert_am < :ignore_exports_since THEN MAX(versionsnummer) ELSE ~0 END AS max_version
FROM lkr_meldung_export lme FROM lkr_meldung_export lme
JOIN lkr_export le ON (lme.lkr_export = le.id)
WHERE SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) = :year WHERE SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) = :year
GROUP BY cond_id ORDER BY cond_id GROUP BY cond_id ORDER BY cond_id