如何编写更好的 SQL 语句进行数据验证
Posted
技术标签:
【中文标题】如何编写更好的 SQL 语句进行数据验证【英文标题】:How can I write better SQL statement for data validation 【发布时间】:2021-07-31 04:29:17 【问题描述】:我正在编写一个存储过程。在其中,我有使用 if 条件的数据验证。例如,如果第一个条件是成功,我将调用存储过程。如果 if 条件失败,我将调用另一个存储过程。同样,我有 20 多个条件可以在一个存储过程中运行。这会产生性能问题。对于以下场景,我该如何以更好的方式编写。
CREATE PROCEDURE Sample
<@Param1, sysname, @p1> <Datatype_For_Param1, , int> = <Default_Value_For_Param1, , 0>,
<@Param2, sysname, @p2> <Datatype_For_Param2, , int> = <Default_Value_For_Param2, , 0>
AS
BEGIN
IF @ModeClass = 'I'
BEGIN
--Validation 001
IF EXISTS (SELECT rderNumber FROM OrderHeader WHERE OrderNumber = @OrderNumber)
SET @STATE_H001 = 0;
SET @FatalCode ='H001';
SET @FatalFlag = 'F';
EXEC spLinkTrackOrderProcessingResult
@pross, @RunningID, @BatchNumber, @FatalFlag, @RecordType, @OrderNumber,
@Sequence1, @Sequence2, @CustomerCode, @Customerabbreviation, @LoadPlanNumber, @InvoiceNumber,
@JobPlaningNumber, @CompanyCode, @PlantAbbreviation, @ModeClass, @FieldName, @BeforeChangeValue,
@AfterChangeValue, @FatalCode, @FatalMessage, @HeaderErrorFlag, @DetailErrorFlag, @ProcessUser,
@ProcessDate, @SolvedUser, @SolvedDate, @CreateUser, @CreateDate, @ChangeUser,
@ChangeDate, @ByProgram, @ByMachine;
ELSE
BEGIN
SET @STATE_H001 = 1;
END
--Validation 002
IF EXISTS (SELECT top 1 1 FROM OrderDetail WHERE OrderNumber = @OrderNumber)
BEGIN
SET @STATE_H004 = 1;
END
ELSE
BEGIN
SET @STATE_H004 = 0;
SET @FatalCode ='H004';
SET @FatalFlag = 'F';
EXEC spLinkTrackOrderProcessingResult
@pross, @RunningID, @BatchNumber, @FatalFlag, @RecordType, @OrderNumber,
@Sequence1, @Sequence2, @CustomerCode, @Customerabbreviation, @LoadPlanNumber, @InvoiceNumber,
@JobPlaningNumber, @CompanyCode, @PlantAbbreviation, @ModeClass, @FieldName, @BeforeChangeValue,
@AfterChangeValue, @FatalCode, @FatalMessage, @HeaderErrorFlag, @DetailErrorFlag, @ProcessUser,
@ProcessDate, @SolvedUser, @SolvedDate, @CreateUser, @CreateDate, @ChangeUser,
@ChangeDate, @ByProgram, @ByMachine;
END
END
END
GO
【问题讨论】:
基于集合的验证方法是编写一个一次性验证多个条件的查询。 忽略不完整和无效的sql,定义“更好”。 IMO 这种方法非常不寻常,但没有人知道您到底想要完成什么(注意 what,而不是 如何)。此外,除了您之外,没有人知道您的“性能条件”是什么意思。但我猜你以 RBAR 方式使用验证逻辑(作为 ETL 过程的一部分),这就是你的性能问题的根源。 如果你需要为每个条件运行一个存储过程,那么你会有很大的性能问题。可能有一种更全面的方法,根本不使用存储过程。这只是一个建议,因为您的问题没有足够的信息来说明更多信息。 【参考方案1】:性能问题是因为您的执行计划很复杂。重新组织您的验证,仅使用您的验证结果调用记录器 SP 一次,并且不要使用 else 子句。
基于您的代码的示例:
CREATE PROCEDURE Sample
<@Param1, sysname, @p1> <Datatype_For_Param1, , int> = <Default_Value_For_Param1, , 0>,
<@Param2, sysname, @p2> <Datatype_For_Param2, , int> = <Default_Value_For_Param2, , 0>
AS
BEGIN
IF @ModeClass = 'I'
BEGIN
SET @STATE_H001 = 1;
SET @STATE_H004 = 1;
--Validation 001
IF EXISTS (SELECT rderNumber FROM OrderHeader WHERE OrderNumber = @OrderNumber)
BEGIN
SET @STATE_H001 = 0;
SET @FatalCode ='H001';
SET @FatalFlag = 'F';
END;
--Validation 002
IF @STATE_H001 = 1 and NOT EXISTS (SELECT top 1 1 FROM OrderDetail WHERE OrderNumber = @OrderNumber)
BEGIN
SET @STATE_H004 = 0;
SET @FatalCode ='H004';
SET @FatalFlag = 'F';
END;
END
if @STATE_H001 = 0 or @STATE_H004 = 0
EXEC spLinkTrackOrderProcessingResult
@pross, @RunningID, @BatchNumber, @FatalFlag, @RecordType, @OrderNumber,
@Sequence1, @Sequence2, @CustomerCode, @Customerabbreviation, @LoadPlanNumber, @InvoiceNumber,
@JobPlaningNumber, @CompanyCode, @PlantAbbreviation, @ModeClass, @FieldName, @BeforeChangeValue,
@AfterChangeValue, @FatalCode, @FatalMessage, @HeaderErrorFlag, @DetailErrorFlag, @ProcessUser,
@ProcessDate, @SolvedUser, @SolvedDate, @CreateUser, @CreateDate, @ChangeUser,
@ChangeDate, @ByProgram, @ByMachine;
END
GO
【讨论】:
以上是关于如何编写更好的 SQL 语句进行数据验证的主要内容,如果未能解决你的问题,请参考以下文章
如何在 WHERE 子句中编写带有 SELECT 语句的 SQL DELETE 语句?