Как создать столбец с вычисляемым значением в HSQLDB?

Рейтинг: 1Ответов: 0Опубликовано: 17.08.2023

В jUnit тестах используется HSQLDB версии 2.7.2 для создания DB в памяти (in-memory DB).
Для создания таблицы используется SQL скрипт, примерное содержимое которого приведено ниже. Проблема заключается в том, что определённый столбец использует вычисляемое значение (computed) используя значения нескольких других столбцов, которые могут содержать NULL значения. Это вычисляемое значение используется как некий ключ (даже не спрашивайте меня почему так - кровавый энтерпрайз) и использует разделитель между значениями. Ожидаемое/требуемое поведение таково, что при NULL-значении разделитель всё равно должен присутствовать.

-- SQL скрипт src/test/resources/t.sql

CREATE TABLE t(
id int GENERATED ALWAYS AS IDENTITY(START WITH 1) NOT NULL,
first_name varchar(50) NULL,
middle_name varchar(50) NULL,
last_name varchar(50) NULL,
full_name varchar(150) GENERATED ALWAYS AS (first_name || ',' || middle_name || ',' || last_name)
-- так тоже пробовал
-- full_name varchar(150) GENERATED ALWAYS AS (CONCAT(first_name, ',', middle_name, ',', last_name))
-- full_name varchar(150) GENERATED ALWAYS AS (CONCAT_WS(first_name, ',', middle_name, ',', last_name))
);
COMMIT;

INSERT INTO t (first_name, middle_name, last_name) VALUES ('a', NULL, 'b');
INSERT INTO t (first_name, middle_name, last_name) VALUES ('c', 'd', 'e');
INSERT INTO t (first_name, middle_name, last_name) VALUES ('f', NULL, 'g');
COMMIT;

Пример создания вычисляемого столбца приведён в документации.

Также пробовал использовать CONCAT и дополнительно указывал в строке подключения параметр sql.concat_nulls=false и sql.concat_nulls=true, так как согласно документации при наличии NULL хотя бы у одного конкатенируемого значения CONCAT вернёт NULL, но никакого эффекта этот параметр строки подключения не принёс. В приведённом примере вычисляемые значения (full_name) будут a,b, c,d,e и ``, так как ни одно из используемых значений не содержит NULL, а необходимые значения должны быть a,,b, c,d,e и f,,g.

Другими словами, оба приведённых варианта создания столбца с вычисляемым значением не работают с NULL.

Каким образом создать вычисляемый столбец используя значения других столбцов содержащих NULL в HSQLDB?


Использование CONCAT_WS

Akina предложил использовать CONCAT_WS, и да это работает, но в этом случае NULL-значениях игнорируются и вместо a,,b или f,,g мы получаем a,b и f,g соответственно (вне зависимости от параметра sql.concat_nulls в строке подключения).


Примерное использование

<!-- фрагмент pom.xml -->
<!-- https://mvnrepository.com/artifact/org.hsqldb/hsqldb -->
<dependency>
    <groupId>org.hsqldb</groupId>
    <artifactId>hsqldb</artifactId>
    <version>${hsqldb}</version>
    <scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hsqldb/sqltool -->
<dependency>
    <groupId>org.hsqldb</groupId>
    <artifactId>sqltool</artifactId>
    <version>${hsqldb}</version>
    <scope>test</scope>
</dependency>
// фрагмент jUnit теста
static Connection getConnection() throws SQLException
{
    return DriverManager.getConnection("jdbc:hsqldb:mem:testdb;"
        + "sql.lowercase_ident=true;"
        + "sql.enforce_names=true;"
        + "sql.enforce_refs=true;"
        + "sql.truncate_trailing=false;"
        + "get_column_name=true"
        + "shutdown=false"
        + "sql.syntax_mss=true"
        + "hsqldb.applog=3"
        + "hsqldb.sqllog=3"
        // хоть true, хоть false - одно и то-же поведение
        // + "sql.concat_nulls=true"
        + "sql.concat_nulls=false", "SA", "");
}

@Test
void computedColumnTest() throws SQLException, IOException, SqlToolError
{
    try (Connection _con = getConnection())
    {
        java.sql.Statement _stmt = _con.createStatement();

        // так выбрасывает исключение
        // java.sql.SQLSyntaxErrorException: unexpected token: CONCAT
        // _stmt.execute("SET DATABASE SQL SYNTAX CONCAT NULLS FALSE");
        
        var _file = new File(this.getClass().getResource( "/t.sql" ).getFile());
        var _sqlFile = new SqlFile(_file);
        _sqlFile.setConnection( _con );
        _sqlFile.execute();

        String _sql = "SELECT id, first_name, middle_name, last_name, full_name FROM t";
        ResultSet _resultSet = _stmt.executeQuery( _sql );
        while(_resultSet.next())
        {
            int _id = _resultSet.getInt( 1 );
            String _firstName = _resultSet.getString( 2 );
            String _middleName = _resultSet.getString( 3 );
            String _lastName = _resultSet.getString( 4 );
            String _fullName = _resultSet.getString( 5 );
        }
        _stmt.execute( "SHUTDOWN" );
    }
}

Ссылки на документацию HSQLDB

Ответы

Ответов пока нет.