有没有更好的方法来组织和使这个SQL查询更具可读性?

时间:2010-07-06 22:46:11

标签: sql sql-server code-organization

我继承了一个我正在为报告系统工作的SQL。系统以采购订单为中心,当它们被创建,已发送,已确认和已确认时。这些州是一个进步的国家。我正在审查的SQL部分如下所示,来自WHERE子句:

OR (CreateJob.endtime is NULL and DATEDIFF(hour, buy_date, getdate()) > Vendor.expected_create_hours)
OR (TransmitJob.endtime is NULL and DATEDIFF(hour, CreateJob.endtime, getdate()) > Vendor.expected_transmit_hours)
OR (AcknowledgeJob.endtime is NULL and DATEDIFF(hour, TransmitJob.endtime, getdate()) > Vendor.expected_acknowledge_hours)
OR (ConfirmJob.endtime is NULL and DATEDIFF(hour, AcknowledgeJob.endtime, getdate()) > Vendor.expected_confirm_hours)

我发现,由于作业失败,CreateJob可能没有结束时间。但是,作业可以执行多个采购订单,因此有时实际创建了给定的PO,但是作业没有收到结束时间,因为兄弟姐妹后来失败了。这会创建一个状态,其中状态仍然为PO进展,但它仍然显示在此问题报告上,因为CreateJob.endtime为NULL。

首先,上面的系统和架构存在一些明显的错误,但这与我目前处理的问题是一个单独的问题。

似乎我可以通过基本上将渐进式检查添加为AND语句来修复报告。因此,对CreateJob的第一次检查也会改变:

(     (CreateJob.endtime is NULL and DATEDIFF(hour, buy_date, getdate()) > Vendor.expected_create_hours) 
  AND (TransmitJob.endtime is NULL and DATEDIFF(hour, CreateJob.endtime, getdate()) > Vendor.expected_transmit_hours) 
  AND (AcknowledgeJob.endtime is NULL and DATEDIFF(hour, TransmitJob.endtime, getdate()) > Vendor.expected_acknowledge_hours) 
  AND (ConfirmJob.endtime is NULL and DATEDIFF(hour, AcknowledgeJob.endtime, getdate()) > Vendor.expected_confirm_hours))

这是丑陋的,并开始混淆被遗忘的东西。有什么方法可以在SQL中执行以下等效操作吗?基本上是某种宏或#define系统?

CreateFailed = (CreateJob.endtime is NULL and DATEDIFF(hour, buy_date, getdate()) > Vendor.expected_create_hours)
TransmitFailed = (TransmitJob.endtime is NULL and DATEDIFF(hour, CreateJob.endtime, getdate()) > Vendor.expected_transmit_hours)
AcknowledgeFailed = (AcknowledgeJob.endtime is NULL and DATEDIFF(hour, TransmitJob.endtime, getdate()) > Vendor.expected_acknowledge_hours)
ConfirmFailed = (ConfirmJob.endtime is NULL and DATEDIFF(hour, AcknowledgeJob.endtime, getdate()) > Vendor.expected_confirm_hours)


OR (CreateFailed AND TransmitFailed AND AcknowledgeFailed AND ConfirmFailed)
OR (TransmitFailed AND AcknowledgeFailed AND ConfirmFailed)
OR (AcknowledgeFailed AND ConfirmFailed)
OR (ConfirmFailed)

如果我想要做的事情有一个共同的术语或名称,也许有人可以将它添加到标题中?

2 个答案:

答案 0 :(得分:2)

一个侧面点 - 您是否提供了生产代码摘录的代码段?如果是这样,您可以仅使用ConfirmFailed条件替换整个块,因为它对您显示的所有WHERE条件都是通用的,并且可以单独满足它。

虽然它没有直接回答您提出的问题,但简化代码的方法是在预处理步骤中计算每个Failed指标的值 - 具体取决于您的环境,这可能是CTE,临时表或视图。这样,所有逻辑都在一个地方 - 如果在查询中多次需要该值,这在例如SELECTWHERE子句中非常有用。

答案 1 :(得分:1)

  

[是]有一个共同的术语或名称   我想做什么......?

抽象?

您可以将每个CreateFailed = ..., TransmitFailed = ...等逻辑隐藏到自己的VIEW或CTE中,然后您的主查询只能查看其中一个表中是否存在作业,例如(伪SQL):

SELECT Jobs.job_ID, ...
  FROM Jobs
 WHERE EXISTS (
               SELECT * 
                 FROM CreatedFailedJobs AS T1
                WHERE Jobs.job_ID = T1.job_ID
               )
       OR EXISTS (
                  SELECT * 
                    FROM TransmitFailedJobs AS T1
                   WHERE Jobs.job_ID = T1.job_ID
                  )
       OR EXISTS (
                  SELECT * 
                    FROM AcknowledgeFailedJobs AS T1
                   WHERE Jobs.job_ID = T1.job_ID
                  )
       OR EXISTS (
                  SELECT * 
                    FROM ConfirmFailedJobs AS T1
                   WHERE Jobs.job_ID = T1.job_ID
                  );

这是扩展的CTE想法(伪SQL):

WITH CreateFailedJobs (job_ID, ...)
AS
(
 SELECT Jobs.job_ID, ...
   FROM ...
  WHERE CreateJob.endtime is NULL 
        AND DATEDIFF(hour, .SomeTable.buy_date, getdate()) 
               > Vendor.expected_create_hours
), 
TransmitFailedJobs (job_ID, ...)
AS
(
 SELECT Jobs.job_ID, ...
   FROM ...
  WHERE TransmitJob.endtime is NULL 
        AND DATEDIFF(hour, CreateJob.endtime, getdate()) 
               > Vendor.expected_transmit_hours
), 
AcknowledgeFailedJobs (job_ID, ...)
AS
(
 SELECT Jobs.job_ID, ...
   FROM ...
  WHERE AcknowledgeJob.endtime is NULL 
        AND DATEDIFF(hour, TransmitJob.endtime, getdate()) 
               > Vendor.expected_acknowledge_hours
), 
ConfirmFailedJobs (job_ID, ...)
AS
(
 SELECT Jobs.job_ID, ...
   FROM ...
  WHERE ConfirmJob.endtime is NULL 
        AND DATEDIFF(hour, AcknowledgeJob.endtime, getdate()) 
               > Vendor.expected_confirm_hours)
)
SELECT Jobs.job_ID, ...
  FROM Jobs
 WHERE EXISTS (
               SELECT * 
                 FROM CreatedFailedJobs AS T1
                WHERE Jobs.job_ID = T1.job_ID
               )
       OR EXISTS (
                  SELECT * 
                    FROM TransmitFailedJobs AS T1
                   WHERE Jobs.job_ID = T1.job_ID
                  )
       OR EXISTS (
                  SELECT * 
                    FROM AcknowledgeFailedJobs AS T1
                   WHERE Jobs.job_ID = T1.job_ID
                  )
       OR EXISTS (
                  SELECT * 
                    FROM ConfirmFailedJobs AS T1
                   WHERE Jobs.job_ID = T1.job_ID
                  );

我不确定这对性能有好处,但可读性是目标,无论如何这个报告都可以离线运行。

相关问题