diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/AbstractEventJdbcTableManager.java b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/AbstractEventJdbcTableManager.java index 074febf2d48e..f805967cbae5 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/AbstractEventJdbcTableManager.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/AbstractEventJdbcTableManager.java @@ -120,9 +120,8 @@ protected String getColumnExpression(ValueType valueType, String columnExpressio } else if (valueType.isInteger()) { return getCastExpression(columnExpression, NUMERIC_REGEXP, sqlBuilder.dataTypeBigInt()); } else if (valueType.isBoolean()) { - return String.format( - "case when %1$s = 'true' then 1 when %1$s = 'false' then 0 else null end", - columnExpression); + return sqlBuilder.ifThenElse( + columnExpression + " = 'true'", "1", columnExpression + " = 'false'", "0", "null"); } else if (valueType.isDate()) { return getCastExpression(columnExpression, DATE_REGEXP, sqlBuilder.dataTypeTimestamp()); } else if (valueType.isGeo() && isSpatialSupport()) { @@ -146,8 +145,9 @@ protected String getColumnExpression(ValueType valueType, String columnExpressio */ protected String getCastExpression(String columnExpression, String filterRegex, String dataType) { String filter = sqlBuilder.regexpMatch(columnExpression, filterRegex); - return String.format( - "case when %s then cast(%s as %s) else null end", filter, columnExpression, dataType); + String result = String.format("cast(%s as %s)", columnExpression, dataType); + + return sqlBuilder.ifThen(filter, result); } @Override diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/table/AbstractEventJdbcTableManagerTest.java b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/table/AbstractEventJdbcTableManagerTest.java index a4ea5e5fa65f..b26200ffb396 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/table/AbstractEventJdbcTableManagerTest.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/table/AbstractEventJdbcTableManagerTest.java @@ -74,7 +74,7 @@ void testGetCastExpression() { """ case when eventdatavalues #>> '{GieVkTxp4HH, value}' ~* '^(-?[0-9]+)(\\.[0-9]+)?$' \ then cast(eventdatavalues #>> '{GieVkTxp4HH, value}' as double precision) \ - else null end"""; + end"""; String actual = manager.getCastExpression( @@ -91,7 +91,7 @@ void testGetSelectExpressionNumber() { """ case when eventdatavalues #>> '{GieVkTxp4HH, value}' ~* '^(-?[0-9]+)(\\.[0-9]+)?$' \ then cast(eventdatavalues #>> '{GieVkTxp4HH, value}' as double precision) \ - else null end"""; + end"""; String actual = manager.getColumnExpression(ValueType.NUMBER, "eventdatavalues #>> '{GieVkTxp4HH, value}'"); @@ -103,7 +103,9 @@ then cast(eventdatavalues #>> '{GieVkTxp4HH, value}' as double precision) \ void testGetSelectExpressionBoolean() { String expected = """ - case when eventdatavalues #>> '{Xl3voRRcmpo, value}' = 'true' then 1 when eventdatavalues #>> '{Xl3voRRcmpo, value}' = 'false' then 0 else null end"""; + case when eventdatavalues #>> '{Xl3voRRcmpo, value}' = 'true' then 1 \ + when eventdatavalues #>> '{Xl3voRRcmpo, value}' = 'false' then 0 \ + else null end"""; String actual = manager.getColumnExpression( @@ -118,7 +120,7 @@ void testGetSelectExpressionDate() { """ case when eventdatavalues #>> '{AL04Wbutskk, value}' ~* '^\\d{4}-\\d{2}-\\d{2}(\\s|T)?((\\d{2}:)(\\d{2}:)?(\\d{2}))?(|.(\\d{3})|.(\\d{3})Z)?$' \ then cast(eventdatavalues #>> '{AL04Wbutskk, value}' as timestamp) \ - else null end"""; + end"""; String actual = manager.getColumnExpression(ValueType.DATE, "eventdatavalues #>> '{AL04Wbutskk, value}'"); diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/table/JdbcEventAnalyticsTableManagerDorisTest.java b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/table/JdbcEventAnalyticsTableManagerDorisTest.java index 5b2bca0f3ec1..3e9a5a2a67dd 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/table/JdbcEventAnalyticsTableManagerDorisTest.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/table/JdbcEventAnalyticsTableManagerDorisTest.java @@ -162,16 +162,16 @@ void verifyGetTableWithDataElements() { String aliasA = "json_unquote(json_extract(eventdatavalues, '$.%s.value')) as `%s`"; String aliasB = - "case when json_unquote(json_extract(eventdatavalues, '$.%s.value')) regexp '^(-?[0-9]+)(\\.[0-9]+)?$' then cast(json_unquote(json_extract(eventdatavalues, '$.%s.value')) as double) else null end as `%s`"; + "case when json_unquote(json_extract(eventdatavalues, '$.%s.value')) regexp '^(-?[0-9]+)(\\.[0-9]+)?$' then cast(json_unquote(json_extract(eventdatavalues, '$.%s.value')) as double) end as `%s`"; String aliasC = "case when json_unquote(json_extract(eventdatavalues, '$.%s.value')) = 'true' then 1 when json_unquote(json_extract(eventdatavalues, '$.%s.value')) = 'false' then 0 else null end as `%s`"; String aliasD = - "case when json_unquote(json_extract(eventdatavalues, '$.%s.value')) regexp '^\\d{4}-\\d{2}-\\d{2}(\\s|T)?((\\d{2}:)(\\d{2}:)?(\\d{2}))?(|.(\\d{3})|.(\\d{3})Z)?$' then cast(json_unquote(json_extract(eventdatavalues, '$.%s.value')) as datetime) else null end as `%s`"; + "case when json_unquote(json_extract(eventdatavalues, '$.%s.value')) regexp '^\\d{4}-\\d{2}-\\d{2}(\\s|T)?((\\d{2}:)(\\d{2}:)?(\\d{2}))?(|.(\\d{3})|.(\\d{3})Z)?$' then cast(json_unquote(json_extract(eventdatavalues, '$.%s.value')) as datetime) end as `%s`"; String aliasE = "json_unquote(json_extract(eventdatavalues, '$.%s.value')) as `%s`"; String aliasF = "(select ou.name from dhis2.public.`organisationunit` ou where ou.uid = json_unquote(json_extract(eventdatavalues, '$.%s.value'))) as `%s`"; String aliasG = - "case when json_unquote(json_extract(eventdatavalues, '$.%s.value')) regexp '^(-?[0-9]+)(\\.[0-9]+)?$' then cast(json_unquote(json_extract(eventdatavalues, '$.%s.value')) as bigint) else null end as `%s`"; + "case when json_unquote(json_extract(eventdatavalues, '$.%s.value')) regexp '^(-?[0-9]+)(\\.[0-9]+)?$' then cast(json_unquote(json_extract(eventdatavalues, '$.%s.value')) as bigint) end as `%s`"; AnalyticsTableUpdateParams params = AnalyticsTableUpdateParams.newBuilder() diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/table/JdbcEventAnalyticsTableManagerTest.java b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/table/JdbcEventAnalyticsTableManagerTest.java index 15e1eb3b9a6d..7bc0ca4c0208 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/table/JdbcEventAnalyticsTableManagerTest.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/table/JdbcEventAnalyticsTableManagerTest.java @@ -378,7 +378,7 @@ void verifyGetTableWithDataElements() { String aliasD2 = """ case when eventdatavalues #>> '{deabcdefghP, value}' ~* '^(-?[0-9]+)(\\.[0-9]+)?$' \ - then cast(eventdatavalues #>> '{deabcdefghP, value}' as double precision) else null end as "deabcdefghP\""""; + then cast(eventdatavalues #>> '{deabcdefghP, value}' as double precision) end as "deabcdefghP\""""; String aliasD3 = """ case when eventdatavalues #>> '{deabcdefghY, value}' = 'true' then 1 \ @@ -386,13 +386,13 @@ void verifyGetTableWithDataElements() { String aliasD4 = """ case when eventdatavalues #>> '{deabcdefghW, value}' ~* '^\\d{4}-\\d{2}-\\d{2}(\\s|T)?((\\d{2}:)(\\d{2}:)?(\\d{2}))?(|.(\\d{3})|.(\\d{3})Z)?$' \ - then cast(eventdatavalues #>> '{deabcdefghW, value}' as timestamp) else null end as "deabcdefghW\""""; + then cast(eventdatavalues #>> '{deabcdefghW, value}' as timestamp) end as "deabcdefghW\""""; String aliasD5 = "eventdatavalues #>> '{" + d5.getUid() + ", value}' as \"" + d5.getUid() + "\""; String aliasD6 = """ case when eventdatavalues #>> '{deabcdefghH, value}' ~* '^(-?[0-9]+)(\\.[0-9]+)?$' \ - then cast(eventdatavalues #>> '{deabcdefghH, value}' as bigint) else null end as "deabcdefghH\""""; + then cast(eventdatavalues #>> '{deabcdefghH, value}' as bigint) end as "deabcdefghH\""""; String aliasD7 = """ ST_GeomFromGeoJSON('{\"type\":\"Point\", \"coordinates\":' || (eventdatavalues #>> '{deabcdefghU, value}') || ', "crs":{"type":"name", "properties":{"name":"EPSG:4326"}}}') as "deabcdefghU\""""; diff --git a/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/ClickHouseSqlBuilder.java b/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/ClickHouseSqlBuilder.java index a5f6976377c5..061cd193a178 100644 --- a/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/ClickHouseSqlBuilder.java +++ b/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/ClickHouseSqlBuilder.java @@ -259,6 +259,18 @@ public String ifThenElse(String condition, String resultA, String resultB) { return String.format("if(%s, %s, %s)", condition, resultA, resultB); } + @Override + public String ifThenElse( + String conditionA, + String thenResultA, + String conditionB, + String thenResultB, + String elseResult) { + return String.format( + "multiIf(%s, %s, %s, %s, %s)", + conditionA, thenResultA, conditionB, thenResultB, elseResult); + } + // Statements @Override diff --git a/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/DorisSqlBuilder.java b/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/DorisSqlBuilder.java index 741b98099147..0e90cf60ed1e 100644 --- a/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/DorisSqlBuilder.java +++ b/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/DorisSqlBuilder.java @@ -264,8 +264,20 @@ public String ifThen(String condition, String result) { } @Override - public String ifThenElse(String condition, String resultA, String resultB) { - return String.format("case when %s then %s else %s end", condition, resultA, resultB); + public String ifThenElse(String condition, String thenResult, String elseResult) { + return String.format("case when %s then %s else %s end", condition, thenResult, elseResult); + } + + @Override + public String ifThenElse( + String conditionA, + String thenResultA, + String conditionB, + String thenResultB, + String elseResult) { + return String.format( + "case when %s then %s when %s then %s else %s end", + conditionA, thenResultA, conditionB, thenResultB, elseResult); } // Statements diff --git a/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/PostgreSqlBuilder.java b/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/PostgreSqlBuilder.java index b19fbfeb1287..21166696f930 100644 --- a/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/PostgreSqlBuilder.java +++ b/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/PostgreSqlBuilder.java @@ -291,8 +291,20 @@ public String ifThen(String condition, String result) { } @Override - public String ifThenElse(String condition, String resultA, String resultB) { - return String.format("case when %s then %s else %s end", condition, resultA, resultB); + public String ifThenElse(String condition, String thenResult, String elseResult) { + return String.format("case when %s then %s else %s end", condition, thenResult, elseResult); + } + + @Override + public String ifThenElse( + String conditionA, + String thenResultA, + String conditionB, + String thenResultB, + String elseResult) { + return String.format( + "case when %s then %s when %s then %s else %s end", + conditionA, thenResultA, conditionB, thenResultB, elseResult); } // Statements diff --git a/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/SqlBuilder.java b/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/SqlBuilder.java index 5d2837c57e96..457853313314 100644 --- a/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/SqlBuilder.java +++ b/dhis-2/dhis-support/dhis-support-sql/src/main/java/org/hisp/dhis/db/sql/SqlBuilder.java @@ -342,11 +342,28 @@ public interface SqlBuilder { * Returns a conditional statement. * * @param condition the condition to evaluate. - * @param resultA the result to return if the condition is true. - * @param resultB the result to return if the condition is false. + * @param thenResult the result to return if the condition is true. + * @param elseResult the result to return if the condition is false. * @return a conditional statement. */ - String ifThenElse(String condition, String resultA, String resultB); + String ifThenElse(String condition, String thenResult, String elseResult); + + /** + * Returns a conditional statement. + * + * @param conditionA the first condition to evaluate. + * @param thenResultA the result to return if the first condition is true. + * @param conditionB the second condition to evaluate. + * @param thenResultB the result to return if the second condition is false. + * @param elseResult the result to return if all conditions are false. + * @return a conditional statement. + */ + String ifThenElse( + String conditionA, + String thenResultA, + String conditionB, + String thenResultB, + String elseResult); // Statements diff --git a/dhis-2/dhis-support/dhis-support-sql/src/test/java/org/hisp/dhis/db/sql/ClickHouseSqlBuilderTest.java b/dhis-2/dhis-support/dhis-support-sql/src/test/java/org/hisp/dhis/db/sql/ClickHouseSqlBuilderTest.java index 9e26f64114a3..6d72e9055d70 100644 --- a/dhis-2/dhis-support/dhis-support-sql/src/test/java/org/hisp/dhis/db/sql/ClickHouseSqlBuilderTest.java +++ b/dhis-2/dhis-support/dhis-support-sql/src/test/java/org/hisp/dhis/db/sql/ClickHouseSqlBuilderTest.java @@ -251,6 +251,22 @@ void testIfThenElse() { sqlBuilder.ifThenElse("a.status = 'COMPLETE'", "a.eventdate", "a.scheduleddate")); } + @Test + void testIfThenElseMulti() { + String expected = + """ + multiIf(a.status = 'COMPLETE', a.eventdate, a.status = 'SCHEDULED', a.scheduleddate, a.incidentdate)"""; + + assertEquals( + expected, + sqlBuilder.ifThenElse( + "a.status = 'COMPLETE'", + "a.eventdate", + "a.status = 'SCHEDULED'", + "a.scheduleddate", + "a.incidentdate")); + } + // Statements @Test diff --git a/dhis-2/dhis-support/dhis-support-sql/src/test/java/org/hisp/dhis/db/sql/DorisSqlBuilderTest.java b/dhis-2/dhis-support/dhis-support-sql/src/test/java/org/hisp/dhis/db/sql/DorisSqlBuilderTest.java index d914ebdf1346..ba44eef28b6d 100644 --- a/dhis-2/dhis-support/dhis-support-sql/src/test/java/org/hisp/dhis/db/sql/DorisSqlBuilderTest.java +++ b/dhis-2/dhis-support/dhis-support-sql/src/test/java/org/hisp/dhis/db/sql/DorisSqlBuilderTest.java @@ -235,6 +235,26 @@ void testIfThenElse() { sqlBuilder.ifThenElse("a.status = 'COMPLETE'", "a.eventdate", "a.scheduleddate")); } + @Test + void testIfThenElseMulti() { + String expected = + """ + case \ + when a.status = 'COMPLETE' then a.eventdate \ + when a.status = 'SCHEDULED' then a.scheduleddate \ + else a.incidentdate \ + end"""; + + assertEquals( + expected, + sqlBuilder.ifThenElse( + "a.status = 'COMPLETE'", + "a.eventdate", + "a.status = 'SCHEDULED'", + "a.scheduleddate", + "a.incidentdate")); + } + // Statements @Test diff --git a/dhis-2/dhis-support/dhis-support-sql/src/test/java/org/hisp/dhis/db/sql/PostgreSqlBuilderTest.java b/dhis-2/dhis-support/dhis-support-sql/src/test/java/org/hisp/dhis/db/sql/PostgreSqlBuilderTest.java index 935336050c2b..3a7ff2bd73b5 100644 --- a/dhis-2/dhis-support/dhis-support-sql/src/test/java/org/hisp/dhis/db/sql/PostgreSqlBuilderTest.java +++ b/dhis-2/dhis-support/dhis-support-sql/src/test/java/org/hisp/dhis/db/sql/PostgreSqlBuilderTest.java @@ -261,6 +261,26 @@ void testIfThenElse() { sqlBuilder.ifThenElse("a.status = 'COMPLETE'", "a.eventdate", "a.scheduleddate")); } + @Test + void testIfThenElseMulti() { + String expected = + """ + case \ + when a.status = 'COMPLETE' then a.eventdate \ + when a.status = 'SCHEDULED' then a.scheduleddate \ + else a.incidentdate \ + end"""; + + assertEquals( + expected, + sqlBuilder.ifThenElse( + "a.status = 'COMPLETE'", + "a.eventdate", + "a.status = 'SCHEDULED'", + "a.scheduleddate", + "a.incidentdate")); + } + // Statements @Test