sql-server - 为条件索引生成的 Liquibase 代码在 MS SQL Server 中给出错误

标签 sql-server indexing liquibase filtered-index

我的 SQL Server 数据库中有以下索引

CREATE NONCLUSTERED INDEX XCR_ACTIVE ON dbo.CS_PA_VEH_BASE ( ETL_ACTIVE_FL )
WHERE ETL_ACTIVE_FL = 'N' ON "default";

其中 liquibase 给出以下内容:

<createIndex indexName="XCR_ACTIVE" tableName="CS_PA_VEH_DELTA">
    <column computed="true" name="([ETL_ACTIVE_FL]='N')"/>
</createIndex>

但是当我想执行它时(也在 MS SQL Server 中)我得到以下内容

> **Error:**  (14.2) 05-24-19 11:43:05 (E) (13004:15088) RUN-050304: |Session JOB_ODS_Liquibase Function call <raise_exception ( Liquibase
> update error: 1: Unexpected error running Liquibase: Incorrect syntax
> near '('. [Failed SQL: CREATE NONCLUSTERED INDEX XCR_ACTIVE ON
> [dbo].[CS_PA_VEH_DELTA](([ETL_ACTIVE_FL]='N'))] ) > failed, due to
> error <50316>: <Liquibase update error:-1: Unexpected error running
> Liquibase: Incorrect syntax near '('. [Failed SQL: CREATE NONCLUSTERED
> INDEX XCR_ACTIVE ON [dbo].[CS_PA_VEH_DELTA](([ETL_ACTIVE_FL]='N'))]>.

我希望这不是第一次发生在某人身上。

最佳答案

正如您在 answer 中提到的,Liquibase 中不支持部分/条件/过滤索引。

您尝试做的是使用compated属性来设置过滤器的条件。 Documentation对于计算状态:

The attribute to set to true if the value in name isn't actually a column name but a function. Boolean.

因此,仅当您想以编程方式命名要索引的列时才使用它。因此,您必须使用纯 SQLmodifySql


修改Sql

使用modifySql,您可以在生成的语句之前或之后附加 SQL,或者替换其中的部分内容。如果我们尝试使用追加,它将如下所示:

<changeSet id="create-an-index-modifySql" author="potato">
    <createIndex tableName="CS_PA_VEH_BASE"
                 indexName="XCR_ACTIVE"
                 clustered="false">
       <column name=ETL_ACTIVE_FL>
    </createIndex>
    <modifySql>
        <append value="WHERE ETL_ACTIVE_FL = 'N'">
    </modifySql>
</changeSet>

这将产生以下sql语句:

CREATE NONCLUSTERED INDEX XCR_ACTIVE ON CS_PA_VEH_BASE ( ETL_ACTIVE_FL )
WHERE ETL_ACTIVE_FL = 'N';

这种方法的问题是使用tablespace属性时; WHERE 将附加在 ON tablespace 之后。示例:

<changeSet id="create-an-index-modifySql" author="potato">
    <createIndex tableName="CS_PA_VEH_BASE"
                 indexName="XCR_ACTIVE"
                 tablespace="default"
                 clustered="false">
       <column name=ETL_ACTIVE_FL>
    </createIndex>
    <modifySql>
        <append value="WHERE ETL_ACTIVE_FL = 'N'">
    </modifySql>
</changeSet>
CREATE NONCLUSTERED INDEX XCR_ACTIVE ON CS_PA_VEH_BASE ( ETL_ACTIVE_FL )
ON default WHERE ETL_ACTIVE_FL = 'N';

语法错误。

解决方案是将 modifySqlreplacewith 属性一起使用:

<changeSet id="create-an-index-modifySql" author="potato">
    <createIndex tableName="CS_PA_VEH_BASE"
                 indexName="XCR_ACTIVE"
                 tablespace="default"
                 clustered="false">
       <column name=ETL_ACTIVE_FL>
    </createIndex>
    <modifySql>
        <append replace="ON default" with="WHERE ETL_ACTIVE_FL = 'N' ON default">
    </modifySql>
</changeSet>
CREATE NONCLUSTERED INDEX XCR_ACTIVE ON CS_PA_VEH_BASE ( ETL_ACTIVE_FL )
WHERE ETL_ACTIVE_FL = 'N' ON default;

虽然正确,但我认为它太繁琐并且容易出错。


纯 SQL

最安全的选择是使用 sql 标记创建一个 changeSet,如下所示:

<changeSet id="create-an-index-pure-sql" author="potato">    
    <sql>
        CREATE NONCLUSTERED INDEX XCR_ACTIVE
            ON dbo.CS_PA_VEH_BASE (ETL_ACTIVE_FL)
        WHERE ETL_ACTIVE_FL = 'N' ON "default";
    </sql>
</changeSet>

虽然它不符合 Liquibase 的精神,但我认为它对于过滤索引来说是足够好的解决方案。

关于sql-server - 为条件索引生成的 Liquibase 代码在 MS SQL Server 中给出错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56323977/

相关文章:

sql - 基于多行SQL过滤数据

sql-server - 使用 CDATA 的 SQL Server XML 输出

sql-server - SSRS : filter parameter passed to sub-report

sql - 选择使用联合查询

java - 如何在 Liquibase 中模仿 Hibernate hbm2ddl "create"行为?

javascript - 单击时显示数组中的最后一个索引(在持续更新的数组中)

mysql - 为mysql动态列添加索引

python - 反转索引的行,python

hsqldb - 使用序列将 Liquibase 数据加载到 HSQLDB

csv - 加载与变更日志文件相关的 CSV 文件