有没有更好的方法来编写这个 SQL 查询? (联盟)

Is there a better way to write this SQL query? (UNION)

我尝试在此代码的 WHERE 子句中使用 OR,但我在 TIMESTAMP_FORMAT 函数中遇到错误,但这不是问题,因为它与工作代码中的完全相同使用 UNION 时。

当我在代码中使用 UNION 时,它完美地工作并且我得到了我想要的,但我严重怀疑这是正确的方法。

我想要所有在 UPTEXT 字段上具有以 (PUP) 开头的文本的记录,在 UPLSTD 字段上没有空值并且在 UPLSTD 字段上的最后使用日期早于 12 天 我不想要这里的空值,因为我不能对空值使用 TIMESTAMP_FORMAT 函数。 但我还需要的是所有在 UPTEXT 字段上也有以 (PUP) 开头的文本但在 UPLSTD 字段上有空值并且在 UPCRTD 字段上创建日期早于 12 天的记录。

这是错误代码:

SELECT UPUPRF,
       UPTEXT,
       UPLSTD,
       UPCRTD
    FROM SYSENGTMP.LLDLSTPRF
    WHERE (
              UPTEXT LIKE '(PUP)%'
              AND UPLSTD <> ' '
              AND TIMESTAMP_FORMAT(UPLSTD, 'RRMMDD') < CURRENT_DATE - 12 DAYS)
          OR (
              UPTEXT LIKE '(PUP)%'
              AND UPLSTD = ' '
              AND TIMESTAMP_FORMAT(UPCRTD, 'RRMMDD') < CURRENT_DATE - 12 DAYS);

这是工作代码:

SELECT UPUPRF,
       UPTEXT,
       UPLSTD,
       UPCRTD
    FROM SYSENGTMP.LLDLSTPRF
    WHERE (
            UPTEXT LIKE '(PUP)%'
            AND UPLSTD <> ' '
            AND TIMESTAMP_FORMAT(UPLSTD, 'RRMMDD') < CURRENT_DATE - 12 DAYS)
UNION
    SELECT UPUPRF,
           UPTEXT,
           UPLSTD,
           UPCRTD
        FROM SYSENGTMP.LLDLSTPRF
        WHERE (
                UPTEXT LIKE '(PUP)%'
                AND UPLSTD = ' '
                AND TIMESTAMP_FORMAT(UPCRTD, 'RRMMDD') < CURRENT_DATE - 12 DAYS);
``

This is the result of the working UNION code which is exactly what I want.
I don't get any result with the faulty code excep for the error message on the TIMESTAMP_FORMAT.

UPUPRF       UPTEXT                     UPLSTD  UPCRTD
------------------------------------------------------
USER1       (PUP) TEXT ABCDEFG          190805  190805
USER2       (PUP) TEXT ABCDEFG          181113  181113
USER3       (PUP) TEXT ABCDEFG          190728  190625
USER4       (PUP) TEXT ABCDEFG          190726  190613
USER5       (PUP) TEXT ABCDEFG                  190625
USER6       (PUP) TEXT ABCDEFG                  190625
USER7       (PUP) TEXT ABCDEFG                  190625
USER8       (PUP) TEXT ABCDEFG                  180725
USER9       (PUP) TEXT ABCDEFG          190730  190625

做两步:

1) put all relevant data in a temp-table
2) do query over the temp-table

像这样:

1) selection: only relevant rows
SELECT UPUPRF,
       UPTEXT,
       UPLSTD,
       UPCRTD
    into #MyTempTable 
    FROM SYSENGTMP.LLDLSTPRF
    WHERE (UPLSTD <> ' '
              AND UPLSTD = ' ');

2) selection: work on relevant data
// column selection is allready done
  SELECT *
        FROM #MyTempTable 
        WHERE (
                UPTEXT LIKE '(PUP)%'
                AND TIMESTAMP_FORMAT(UPCRTD, 'RRMMDD') < CURRENT_DATE - 12 DAYS);

我真的没有发现您的代码有任何问题...我怀疑实际代码与您显示的不同。

但我这样做的方法是合并匹配的过滤器...

SELECT UPUPRF,
       UPTEXT,
       UPLSTD,
       UPCRTD
    FROM SYSENGTMP.LLDLSTPRF
    WHERE  UPTEXT LIKE '(PUP)%'
              AND ((UPLSTD <> ' ' AND TIMESTAMP_FORMAT(UPLSTD, 'RRMMDD') < CURRENT_DATE - 12 DAYS)
                     OR (UPLSTD = ' ' AND TIMESTAMP_FORMAT(UPCRTD, 'RRMMDD') < CURRENT_DATE - 12 DAYS)
                   );

编辑
如果您使用 NULL 而不是 UPLSTD 的空格会更容易...假设支持的 IBM i 版本,您可以尝试使用 NULLIF() 将空格替换为 NULL 和 coalesce() 到 return 非空白 UPLSTD 或 UPCRTD。

SELECT UPUPRF,
       UPTEXT,
       UPLSTD,
       UPCRTD
    FROM SYSENGTMP.LLDLSTPRF
    WHERE  UPTEXT LIKE '(PUP)%'
              AND TIMESTAMP_FORMAT(coalesce(nullif(UPLSTD,' '), UPCRTD)
                                   , 'RRMMDD'
                                  ) < CURRENT_DATE - 12 DAYS;

我有一个有点疯狂的理论,优化器导致了这个问题。出于性能原因,故障版本可能会尝试 运行 UPLSTD 和 UPCRTD 字段上的 TIMESTAMP_FORMAT,然后 运行 另一个在每个块中进行比较。如果其中之一有错误数据或可能只有空白,则可能会导致错误。

另一方面,union 可能在其他相关比较之后 运行ning TIMESTAMP_FORMAT 函数,因此在它 运行s TIMESTAMP_FORMAT函数。

如果可用,您可能想尝试 运行使用 VisualExplain 对这两个查询进行查询,看看它是如何优化每个查询的。