oracle 实现列子查询时遇到问题[已关闭]

taor4pac  于 2023-03-01  发布在  Oracle
关注(0)|答案(3)|浏览(131)

**已关闭。**此问题需要debugging details。当前不接受答案。

编辑问题以包含desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem。这将有助于其他人回答问题。
3天前关闭。
Improve this question
我试图根据采购工具的第一次交易及其在Oracle数据库中的状态来查找它们的使用寿命。我使用CASE函数创建了一个新列,该列为不具有此状态的工具返回“活动工具”,并返回报废日期(如果有)。然后,我想:根据该列计算工具的使用年限。如果工具仍处于“活动...”状态,则使用今天的日期减去第一个状态日期。如果工具已报废,则应从第一个状态日期减去报废日期。
我可以呈现列,但我不知道如何创建列(多行?)子查询以便引用它。下面的代码是我天真的假设,我知道它不会工作。

SELECT SERIALTOOL.SERIALID,
       SERIALTOOL.ITEMNUMBER,
       MIN (SERIALTOOL.STATUSDATE) AS "Purchase Date",
       CASE
          WHEN SERIALTOOL.STATUS = 5 THEN TO_CHAR (SERIALTOOL.STATUSDATE)
          ELSE 'Active Tool'
       END AS "Scrap Date",
       CASE
          WHEN "Scrap Date" = 'Active Tool'
          THEN CURRENT_DATE - MIN (SERIALTOOL.STATUSDATE)
          ELSE "Scrap Date" - MIN (SERIALTOOL.STATUSDATE)
       END AS "TOOL AGE"
FROM SERVER.SERIALTOOL SERIALTOOL
ghg1uchk

ghg1uchk1#

实际上已经很接近了,为了混合聚合列和非聚合列,必须使用窗口(OVER子句),并且由于在派生列上使用CASE逻辑,因此需要嵌套查询块,如下所示:

SELECT SERIALID,
       ITEMNUMBER,
       "Purchase Date",
       STATUS,
       STATUSDATE,
       CASE
          WHEN STATUS = 5 THEN TO_CHAR (STATUSDATE)
          ELSE 'Active Tool'
       END AS "Scrap Date",
       CASE
          WHEN STATUS != 5 THEN SYSDATE - "Purchase Date"
          ELSE STATUSDATE - "Purchase Date"
       END AS "TOOL AGE"
  FROM (SELECT SERIALID,
               ITEMNUMBER,
               MIN (STATUSDATE) OVER (PARTITION BY serialid) AS "Purchase Date",
               STATUS,
               STATUSDATE
          FROM SERVER.SERIALTOOL)

哦,你可能应该坚持使用Oracle合法的列名,这样你就不需要“”和区分大小写了。所有的大写,除了_和#之外没有特殊的字符,并且以字母字符开头。

dohp0rv5

dohp0rv52#

依据是:

  • serialtool.serialid标识工具
  • serialtool.itemnumber列出每个工具的事务
  • serialtool.itemnumber = 1表示购买交易
  • serialtool.status = 5表示刀具已报废
  • 刀具只能报废一次

我的建议是这样的:

WITH scrapped_tools AS (
    SELECT st.serialid,
           st.itemnumber,
           st.statusdate AS scrapped_date
    FROM   serialtool st
    WHERE  st.status = 5)
SELECT st.serialid,
       st.itemnumber AS purchase_entry,
       st.statusdate AS purchase_date,
       NVL2 (scr.serialid, 'Active', 'Scrapped') AS tool_status,
       NVL2 (scr.serialid,
           SYSDATE - st.statusdate,
           scr.statusdate - st.statusdate) AS tool_age
FROM   serialtool st
           LEFT OUTER JOIN scrapped_tools scr ON st.serialid = scr.serialid
WHERE  st.itemnumber = 1;

对于前面的答案,我更喜欢关键字和Oracle提供的函数使用大写字母;用户定义的名称为小写。
对于NVL2()之前的版本,请使用DECODE (scr.serialid, NULL, 'Active', 'Scrapped')

46scxncf

46scxncf3#

多亏了@rgm575,我意识到有一个“DATEINSERVICE”字段可以使用,并且可以避免使用最早的状态日期。多亏了@paul-w,它给了我大量的子查询信息。此外,为了保持简单,我保留了日期,即使是仍然在使用的项目,并添加了一个额外的列来显示工具的状态。

SELECT a.SERIALID,
         a.ITEMNUMBER,
         a.DATEINSERVICE,
         CASE
            WHEN a.SCRAP_DATE = CURRENT_DATE
            THEN
               ROUND (CURRENT_DATE - a.DATEINSERVICE)
            ELSE
               ROUND (a.SCRAP_DATE - a.DATEINSERVICE)
         END AS TOOL_AGE,
         a.TOOL_STATUS
  FROM (SELECT SERIALTOOL.SERIALID,
               SERIALTOOL.ITEMNUMBER,
               SERIALTOOL.DATEINSERVICE,
               CASE
                  WHEN SERIALTOOL.STATUS = 5 THEN SERIALTOOL.STATUSDATE
                  ELSE CURRENT_DATE
               END AS SCRAP_DATE,
               CASE
                  WHEN SERIALTOOL.STATUS = 5 THEN 'Scrapped'
                  ELSE 'In Service'
               END AS TOOL_STATUS
        FROM SERVER.SERIALTOOL SERIALTOOL
        WHERE (    SERIALTOOL.HOMECRIB = 823
               AND SERIALTOOL.DATEINSERVICE > CURRENT_DATE - 5475)) a

相关问题