Skip to content

Commit 1c33272

Browse files
authored
Merge pull request #52 from NorwegianVeterinaryInstitute/dev
fix: corrected retrieve_PJSdata and standardize_PJSdata
2 parents 640c1ee + 16ed387 commit 1c33272

21 files changed

+755
-69
lines changed

DESCRIPTION

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Package: NVIpjsr
22
Title: Tools to facilitate working with PJS data
3-
Version: 0.2.1
4-
Date: 2025-09-11
3+
Version: 0.2.2
4+
Date: 2026-02-11
55
Authors@R: c(
66
person("Petter", "Hopp", , "Petter.Hopp@vetinst.no", role = c("aut", "cre"),
77
comment = c(ORCID = "0000-0002-8695-0378")),
@@ -20,7 +20,7 @@ Depends:
2020
Encoding: UTF-8
2121
Language: en-GB
2222
Roxygen: list(markdown = FALSE)
23-
RoxygenNote: 7.3.2
23+
RoxygenNote: 7.3.3
2424
Imports:
2525
checkmate (>= 2.1.0),
2626
data.table,

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
YEAR: 2024 - 2025
1+
YEAR: 2024 - 2026
22
COPYRIGHT HOLDER: Norwegian Veterinary Institute
33
ORGANIZATION: Norwegian Veterinary Institute

LICENSE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
BSD 3-Clause License
22

3-
Copyright (c) 2024 - 2025 Norwegian Veterinary Institute
3+
Copyright (c) 2024 - 2026 Norwegian Veterinary Institute
44

55
Redistribution and use in source and binary forms, with or without
66
modification, are permitted provided that the following conditions are met:

NEWS.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,32 @@
1+
# NVIpjsr 0.2.2 - (2026-02-11)
2+
3+
## New features:
4+
5+
- `retrieve_PJSdata` now accepts the input argument `dbinterface`. Valid values
6+
are c("odbc", "RODBC").
7+
8+
9+
## Bug fixes:
10+
11+
- An error when using `retrieve_PJSdata` due to changing format of merknad to
12+
nvarchar(MAX) is fixed. This occured due to using `dbinterface = "odbc"`.
13+
14+
- `standardize_PJSdata` now correct generates the "fagnr" when the data have been retrieved using "odbc".
15+
16+
17+
## Other changes:
18+
19+
- Included variable "anamnese"" in PJS_levels.
20+
21+
- Created help for functions with deprecated arguments from NVIdb.
22+
23+
124
# NVIpjsr 0.2.1 - (2025-09-11)
225

326
## New features:
427

5-
- `add_PJS_code_description` will now translate "delpr_forbehandlingkode" when the arguments `new_column` = `"auto"` and/or `PJS_variable_type` = `"auto"`.
28+
- `add_PJS_code_description` will now translate "delpr_forbehandlingkode" when
29+
the arguments `new_column` = `"auto"` and/or `PJS_variable_type` = `"auto"`.
630

731

832
## Bug fixes:

R/NVIpjsr-deprecated.R

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#' @title Deprecated Functions and Arguments in Package NVIpjsr
2+
#' @description These functions are provided for compatibility with older
3+
#' versions of NVIpjsr only, and may be defunct as soon as the next release.
4+
#' When possible, alternative functions are mentioned. Help pages for
5+
#' deprecated functions are available at \code{help("<function>-deprecated")}.
6+
#' @details The arguments \code{missing_art} and \code{file} in
7+
#' \code{set_disease_parameters} was deprecated from NVIdb v0.11.0 released
8+
#' 2024-01-24. These arguments are replaced by the more meaningful
9+
#' \code{include_missing_art} and \code{selection_parameters}, respectively.
10+
#' If using the old arguments, the input will be transferred to the new
11+
#' arguments.
12+
#'
13+
#' The arguments \code{FUN} and \code{selection_statement} in
14+
#' \code{retrieve_PJSdata} was deprecated from NVIdb v0.11.2 released
15+
#' 2024-04-05. These arguments should instead be included in the list input
16+
#' to \code{selection_parameters}. If using the old arguments, the input
17+
#' will be transferred to \code{selection_parameters}.
18+
#'
19+
#' @param \dots (arguments)
20+
#' @return (results)
21+
#' @name NVIpjsr-deprecated
22+
#' @keywords internal
23+
#'
24+
#' @author Petter Hopp Petter.Hopp@@vetinst.no
25+
#'
26+
#' @examples
27+
#' \dontrun{
28+
#' retrieve_PJSdata(...) ###
29+
#' set_disease_parameters(...) ###
30+
#' }
31+
NULL

R/retrieve_PJSdata.R

Lines changed: 145 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,93 @@
11
#' @title Retrieves data from PJS
22
#' @description Retrieves and standardises PJS data. \code{retrieve_PJSdata} is
3+
#' a wrapper for several \code{NVIpjsr}-functions and the intention of
4+
#' \code{retrieve_PJSdata} is to shorten code and to ensure that a standard
5+
#' procedure is followed when retrieving PJS data, see details. It can only
6+
#' be used for retrieving case data from PJS where the columns "aar",
7+
#' "ansvarlig_seksjon" and "innsendelsenr" are included in the columns. It
8+
#' cannot be used for retrieving data from other tables available in
9+
#' "journal_rapp".
10+
#'
11+
#' @details \code{retrieve_PJSdata} is a wrapper for the following
12+
#' \code{NVIdb}-functions and \code{NVIpjsr}-functions:
13+
#' \itemize{
14+
#' \item Constructs the select statement by a build_query-function (see details)
15+
#' and selection parameters.
16+
#' \item Creates an open ODBC-channel using
17+
#' \ifelse{html}{\code{\link[NVIdb:login_PJS]{login_PJS}}}{\code{NVIdb::login_PJS}}.
18+
#' \item Retrieves the data using the select statement constructed above.
19+
#' \item Standardises the data using
20+
#' \ifelse{html}{\code{\link{standardize_PJSdata}}}{\code{standardize_PJSdata}}.
21+
#' \item Excludes unwanted cases using
22+
#' \ifelse{html}{\code{\link{exclude_from_PJSdata}}}{\code{exclude_from_PJSdata}}.
23+
#' }
24+
#'
25+
#' For the function to run automatically without having to enter PJS user
26+
#' credentials, it is dependent that PJS user credentials have been saved using
27+
#' \code{set_credentials_PJS}.
28+
#' Otherwise, the credentials must be input manually to establish an open
29+
#' ODBC channel.
30+
#'
31+
#' The select statement for PJS can be built giving the selection parameters and
32+
#' input to one of the build_query-functions, i.e.
33+
#' \ifelse{html}{\code{\link{build_query_hensikt}}}{\code{build_query_hensikt}},
34+
#' \ifelse{html}{\code{\link{build_query_one_disease}}}{\code{build_query_one_disease}}
35+
#' and
36+
#' \ifelse{html}{\code{\link{build_query_outbreak}}}{\code{build_query_outbreak}}.
37+
#' The selection parameters can be set by using
38+
#' \ifelse{html}{\code{\link{set_disease_parameters}}}{\code{set_disease_parameters}}.
39+
#' or by giving a list of similar format for input to
40+
#' \code{selection_parameters}, see the build_query-functions for necessary
41+
#' input.
42+
#'
43+
#' \code{retrieve_PJSdata} gives the possibility of giving the select_statement
44+
#' as a string instead of using the build_query-functions. If so, the
45+
#' select_statement should be included in the selection parameters. This
46+
#' should only by done for select statements that previously have been tested
47+
#' and are known to have correct syntax. \code{retrieve_PJSdata} has no
48+
#' possibility of checking the sql syntax before it is submitted to PJS and
49+
#' untested select statements can take a lot of time or stop the function
50+
#' without proper error messages. In the case that both a select_statement
51+
#' and a function with the necessary selection_parameters are given,
52+
#' the select_statement constructed by the function will be used.
53+
#'
54+
#' The output is a named list where each entry is a data frame with PJS data. If
55+
#' the select statement is named, the returned data frame will have that name.
56+
#' If the select statement is unnamed, it will try to identify the first
57+
#' table in the select statement and use this as name. If not possible, the
58+
#' name will be of the format "PJSdata#" where # is the number of the select
59+
#' statement.
60+
61+
#'
62+
#' @param year [\code{numeric}]\cr
63+
#' One year or a vector giving the first and last years that should be selected.
64+
#' Defaults to \code{NULL}.
65+
#' @param selection_parameters [\code{character(1)}]\cr
66+
#' Either the path and file name for an R script that can be sourced and that
67+
#' sets the selection parameters or a named list with the selection parameters
68+
#' (i.e. of the same format as the output of
69+
#' \ifelse{html}{\code{\link{set_disease_parameters}}}{\code{set_disease_parameters}}).
70+
#' Defaults to \code{NULL}.
71+
#' @param FUN \code{deprecated}\cr
72+
#' \code{FUN} should instead be included as input to \code{selection_parameters}.
73+
#' Defaults to \code{NULL}.
74+
#' @param select_statement \code{deprecated}\cr
75+
#' \code{select_statement} should instead be included as input to
76+
#' \code{selection_parameters}. Defaults to \code{NULL}.
77+
#' @param \dots Other arguments to be passed to the underlying functions:
78+
#' \ifelse{html}{\code{\link[NVIdb:login_PJS]{login_PJS}}}{\code{NVIdb::login_PJS}}
79+
#' and
80+
#' \ifelse{html}{\code{\link{exclude_from_PJSdata}}}{\code{exclude_from_PJSdata}}.
81+
#'
82+
#' @return A named list with PJS data.
83+
#'
84+
#' @author Petter Hopp Petter.Hopp@@vetinst.no
85+
#' @name retrieve_PJSdata-deprecated
86+
#' @keywords internal
87+
NULL
88+
#'
89+
#' @title Retrieves data from PJS
90+
#' @description Retrieves and standardises PJS data. \code{retrieve_PJSdata} is
391
#' a wrapper for several \code{NVIdb} - and \code{NVIpjsr} - functions and the intention of
492
#' \code{retrieve_PJSdata} is to shorten code and to ensure that a standard
593
#' procedure is followed when retrieving PJS data, see details. It can only
@@ -50,15 +138,15 @@
50138
#' the select_statement constructed by the function will be used.
51139
#'
52140
#' Be aware that there is a known problem for the R-package "odbc" when selecting
53-
#' long text variables like "anamnese". Such variables need to be put last in
54-
#' the select statement. The variable "anamnese" is included in the main views
55-
#' used for retrieving data from PJS. \code{retrieve_PJSdata} will rewrite
141+
#' long text variables like "anamnese" and "merknad" (for sak). Such variables
142+
#' need to be put last in the select statement. These variables are included
143+
#' in the main views used for retrieving data from PJS. \code{retrieve_PJSdata} will rewrite
56144
#' select statements generated by the \code{build_query}-functions and sql
57145
#' statements starting with "SELECT * FROM 'tablename'", but will not rewrite
58146
#' the sql statement in other situations. If this happens, you must either
59-
#' rewrite the sql statement and put "anamnese" last in the select statement
60-
#' or use the R-package "RODBC" instead. If using "RODBC", you cannot use
61-
#' \code{retrieve_PJSdata}.
147+
#' rewrite the sql statement and put these variables last in the select statement
148+
#' or use the R-package "RODBC" instead by giving the argument
149+
#' \code{dbinterface = "RODBC"}.
62150
#'
63151
#' The output is a named list where each entry is a data frame with PJS data. If
64152
#' the select statement is named, the returned data frame will have that name.
@@ -77,6 +165,9 @@
77165
#' (i.e. of the same format as the output of
78166
#' \code{\link{set_disease_parameters}}).
79167
#' Defaults to \code{NULL}.
168+
#' @param dbinterface [\code{character(1)}]\cr
169+
#' The R-package that is used for interface towards the data base. Valid values
170+
#' are c("odbc", "RODBC"). Defaults to \code{"odbc"}.
80171
#' @param \dots Other arguments to be passed to the underlying functions:
81172
#' \ifelse{html}{\code{\link[NVIdb:login]{NVIdb::login("PJS")}}}{\code{NVIdb::login("PJS")}}
82173
#' and \code{\link{exclude_from_PJSdata}}.
@@ -103,10 +194,16 @@
103194
#' PJSrawdata <- retrieve_PJSdata(year = 2024,
104195
#' selection_parameters = selection_parameters,
105196
#' abroad = "include")
197+
#'
198+
#' # Read PJSdata using RODBC
199+
#' PJSrawdata <- retrieve_PJSdata(year = 2024,
200+
#' selection_parameters = selection_parameters,
201+
#' dbinterface = "RODBC")
106202
#' }
107203
#'
108204
retrieve_PJSdata <- function(year = NULL,
109205
selection_parameters = NULL,
206+
dbinterface = "odbc",
110207
...) {
111208

112209
# CAPTURE DOTS ----
@@ -177,6 +274,8 @@ retrieve_PJSdata <- function(year = NULL,
177274
selection_parameters$utbrudd2select,
178275
selection_parameters$select_statement, add = checks))
179276
NVIcheckmate::assert_non_null(list(unlist(selection_parameters$FUN), selection_parameters$select_statement), add = checks)
277+
checkmate::assert_choice(dbinterface,
278+
choices = c("odbc", "RODBC"), add = checks)
180279

181280
# Report check-results
182281
checkmate::reportAssertions(checks)
@@ -241,35 +340,53 @@ retrieve_PJSdata <- function(year = NULL,
241340
# OPEN ODBC CHANNEL ----
242341
# journal_rapp <- NVIdb::login(dbservice = "PJS", dbinterface = "odbc", ...)
243342
dots1 <- intersect(setdiff(names(formals(NVIdb::login)), c("dbservice", "dbinterface")), names(dots))
244-
journal_rapp <- do.call(NVIdb::login, append(dots[dots1], list(dbservice = "PJS", dbinterface = "odbc")))
343+
344+
# if (dbinterface == "odbc") {
345+
journal_rapp <- do.call(NVIdb::login, append(dots[dots1], list(dbservice = "PJS", dbinterface = dbinterface)))
346+
# }
347+
# journal_rapp <- do.call(NVIdb::login, append(dots[dots1], list(dbservice = "PJS", dbinterface = "RODBC")))
245348

246349
PJSdata <- vector("list", length = length(select_statement))
247350

248351
# PERFORM SELECTION AND STANDARDISATION FOR EACH SELECT STATEMENT ----
249352
for (i in c(1:length(select_statement))) {
250353

251-
# MOVE anamnese LAST IN SELECTION STATEMENT ----
252-
# Identify table in the first select clause in sql statement
253-
db_table <- sub("SELECT[[:space:]]*\\*[[:space:]]*FROM[[:space:]]*([^[:space:]]*).*",
254-
"\\1",
255-
select_statement[[i]], ignore.case = TRUE)
256-
# List fields in the db_table
257-
if (nchar(db_table) > 0 && regexpr("[[:space:],\\*]", db_table) < 0) {
258-
fields <- DBI::dbListFields(conn = journal_rapp, name = db_table)
259-
# Put anamnese last in select clause if exist in the db_table
260-
if ("anamnese" %in% tolower(fields)) {
261-
fields <- paste0(fields, collapse = ", ")
262-
fields <- paste0(sub("anamnese, ", "", fields, ignore.case = TRUE), ", anamnese")
263-
select_statement[[i]] <- sub(paste0("SELECT[[:space:]]*\\*[[:space:]]*FROM[[:space:]]*", db_table),
264-
paste("SELECT", fields, "FROM", db_table),
265-
select_statement[[i]],
266-
ignore.case = TRUE)
354+
if (dbinterface == "odbc") {
355+
# MOVE anamnese LAST IN SELECTION STATEMENT ----
356+
# Identify table in the first select clause in sql statement
357+
db_table <- sub("SELECT[[:space:]]*\\*[[:space:]]*FROM[[:space:]]*([^[:space:]]*).*",
358+
"\\1",
359+
select_statement[[i]], ignore.case = TRUE)
360+
# List fields in the db_table
361+
if (nchar(db_table) > 0 && regexpr("[[:space:],\\*]", db_table) < 0) {
362+
fields <- DBI::dbListFields(conn = journal_rapp, name = db_table)
363+
# Put anamnese last in select clause if exist in the db_table
364+
if ("anamnese" %in% tolower(fields) | "merknad" %in% tolower(fields)) {
365+
fields <- paste0(fields, collapse = ", ")
366+
if (regexpr("merknad", fields, ignore.case = TRUE) > 0) {
367+
fields <- paste0(sub("merknad, ", "", fields, ignore.case = TRUE), ", merknad")
368+
}
369+
if (regexpr("anamnese", fields, ignore.case = TRUE) > 0) {
370+
fields <- paste0(sub("anamnese, ", "", fields, ignore.case = TRUE), ", anamnese")
371+
}
372+
select_statement[[i]] <- sub(paste0("SELECT[[:space:]]*\\*[[:space:]]*FROM[[:space:]]*", db_table),
373+
paste("SELECT", fields, "FROM", db_table),
374+
select_statement[[i]],
375+
ignore.case = TRUE)
376+
}
267377
}
378+
379+
# READ DATA FROM PJS ----
380+
PJSdata[[i]] <- DBI::dbGetQuery(con = journal_rapp,
381+
statement = select_statement[[i]])
382+
}
383+
384+
if (dbinterface == "RODBC") {
385+
PJSdata[[i]] <- RODBC::sqlQuery(journal_rapp,
386+
query = select_statement[[i]],
387+
as.is = TRUE)
268388
}
269389

270-
# READ DATA FROM PJS ----
271-
PJSdata[[i]] <- DBI::dbGetQuery(con = journal_rapp,
272-
statement = select_statement[[i]])
273390
# STANDARDIZE DATA ----
274391
PJSdata[[i]] <- standardize_PJSdata(PJSdata = PJSdata[[i]], dbsource = dbsource[i])
275392

@@ -280,7 +397,8 @@ retrieve_PJSdata <- function(year = NULL,
280397
}
281398

282399
# CLOSE ODBC CHANNEL ----
283-
DBI::dbDisconnect(journal_rapp)
400+
if (dbinterface == "odbc") {DBI::dbDisconnect(journal_rapp)}
401+
if (dbinterface == "RODBC") {RODBC::odbcClose(journal_rapp)}
284402

285403
# RETURN RESULT ----
286404
# Give name to each entry in the list of PJSdata

0 commit comments

Comments
 (0)