【问题标题】:(Nested?) Select statement with MAX and WHERE clause(嵌套?)带有 MAX 和 WHERE 子句的 Select 语句
【发布时间】:2016-11-08 21:12:58
【问题描述】:

我正在研究一组数据,以便从 Oracle 数据库生成报告。

数据在两个表中:

  1. 供应
  2. 设备

只有一列链接两个表:

  • SUPPLY.DEVICE_ID
  • DEVICE.ID

在 SUPPLY 中,有这些数据:(Markdown 效果不佳。它应该显示一个表格)

| DEVICE_ID     | COLOR_TYPE    | SERIAL        | UNINSTALL_DATE        |
|-----------    |------------   |-------------- |---------------------  |
| 1232          | 1             | CAP857496     | 08/11/2016,19:10:50   |
| 5263          | 2             | CAP57421      | 07/11/2016,11:20:00   |
| 758           | 3             | CBO753421869  | 07/11/2016,04:25:00   |
| 758           | 4             | CC9876543     | 06/11/2016,11:40:00   |
| 8575          | 4             | CVF75421      | 05/11/2016,23:59:00   |
| 758           | 4             | CAP67543      | 30/09/2016,11:00:00   |

在 DEVICE 中,我必须选择所有列(或多或少),但每一行都是唯一的。

我需要实现的是: 对于每个 SUPPLY.DEVICE_ID 和 SUPPLY.COLOR_TYPE,我需要最近的 ROW -> MAX(UNINSTALL_DATE)

加入 或多或少是 DEVICE 中的所有列。

最后我应该有这样的东西:

| ACCOUNT_CODE  | MODEL     | DEVICE.SERIAL     | DEVICE_ID     | COLOR_TYPE    | SUPPLY.SERIAL     | UNINSTALL_DATE        |
|-------------- |-------    |---------------    |-----------    |------------   |---------------    |---------------------  |
| BUSTO         | MS410     | LM753             | 1232          | 1             | CAP857496         | 08/11/2016,19:10:50   |
| MACCHI        | MX310     | XC876             | 5263          | 2             | CAP57421          | 07/11/2016,11:20:00   |
| ASL_COMO      | MX711     | AB123             | 758           | 3             | CBO753421869      | 07/11/2016,04:25:00   |
| ASL_COMO      | MX711     | AB123             | 758           | 4             | CC9876543         | 06/11/2016,11:40:00   |
| ASL_VARESE    | X950      | DE8745            | 8575          | 4             | CVF75421          | 05/11/2016,23:59:00   |

到目前为止,使用嵌套选择如下:

SELECT DEVICE_ID,COLOR_TYPE,SERIAL,UNINSTALL_DATE FROM 
(SELECT SELECT DEVICE_ID,COLOR_TYPE,SERIAL,UNINSTALL_DATE 
FROM SUPPLY WHERE DEVICE_ID = '123456' ORDER BY UNINSTALL_DATE DESC) 
WHERE ROWNUM <= 1

在尝试
MAX(UNISTALL_DATE) or HIGHEST(UNISTALL_DATE) 之后,我设法在 UNISTALL_DATE 列上获得了最高值。

我也试过了:

SELECT SUPPLY.DEVICE_ID, SUPPLY.COLOR_TYPE, .... 
FROM SUPPLY,DEVICE WHERE SUPPLY.DEVICE_ID = DEVICE.ID

它有效,但给了我所有的项目,基本上它是两个表的合并。 当我尝试缩小所选数据的范围时,我得到错误或空结果。

我开始怀疑无法获取这些数据,我开始将数据导出到 excel 中并从那里开始工作,但我希望在放弃之前有人可以帮助我...

提前谢谢你。

【问题讨论】:

    标签: oracle select join nested max


    【解决方案1】:

    对于每个 SUPPLY.DEVICE_ID 和 SUPPLY.COLOR_TYPE,我需要最近的 ROW -> MAX(UNINSTALL_DATE)

    这样使用ROW_NUMBER函数:

    SELECT s.*,
           row_number() OVER (
                 PARTITION BY DEVICE_ID, COLOR_TYPE
                 ORDER BY UNINSTALL_DATE DESC
           ) As RN
    FROM SUPPLY s
    

    此查询用 RN=1 标记最近的行


    与 DEVICE 中的所有列或多或少地加入。

    只需将上述查询加入到 DEVICE 表中

    SELECT d.*, 
           x.COLOR_TYPE,
           x.SERIAL,
           x.UNINSTALL_DATE
    FROM (
       SELECT s.*,
              row_number() OVER (
                    PARTITION BY DEVICE_ID, COLOR_TYPE
                    ORDER BY UNINSTALL_DATE DESC
              ) As RN
       FROM SUPPLY s
    ) x
    JOIN DEVICE d
    ON d.DEVICE_ID = x.DEVICE_ID AND x.RN=1
    

    【讨论】:

      【解决方案2】:

      好的 - 所以你也可以按 device_id, color_typeselect max(uninstall_date) 分组,然后加入另一个表。但是您会错过最近一行的serial 值(对于device_id, color_type 的每个组合)。

      有几种方法可以解决这个问题。您对rownum 的尝试很接近,但问题是您需要在每个“组”中订购(按device_id, color_type)并从每个组中获取第一行。我相信有人会按照这些思路发布解决方案,使用row_number()rank() 或者max(uninstall_date) 的分析版本。

      当您只需要每个组的“顶部”行时,您可以使用keep (dense_rank first/last) - 这可能会更有效 - 像这样:

      select   device_id, color_type, 
               max(serial) keep (dense_rank last order by uninstall_date) as serial, 
               max(uninstall_date) as uninstall_date
      from     supply
      group by device_id, color_type
      ;
      

      然后加入另一个表。注意:dense_rank last 将为每个组选择具有最近(最大)日期的行或行。如果有平局,那就不止一排;然后 serial 将是最近日期的那些行中的最大值(按字典顺序)。您还可以选择最小,或添加一些订单以便选择特定的订单(您没有讨论这种可能性)。

      【讨论】:

        【解决方案3】:
        SELECT 
              d.ACCOUNT_CODE, d.DNS_HOST_NAME,d.IP_ADDRESS,d.MODEL_NAME,d.OVERRIDE_SERIAL_NUMBER,d.SERIAL_NUMBER,
              s.COLOR, s.SERIAL_NUMBER, s.UNINSTALL_TIME
        FROM (
              SELECT s.DEVICE_ID, s.LAST_LEVEL_READ, s.SERIAL_NUMBER,TRUNC(s.UNINSTALL_TIME), row_number() 
        OVER (
              PARTITION BY DEVICE_ID, COLOR
              ORDER BY UNINSTALL_TIME DESC
              ) As RN
        FROM SUPPLY s 
        WHERE s.UNINSTALL_TIME IS NOT NULL AND s.SERIAL_NUMBER IS NOT NULL
                )
        
        JOIN DEVICE d
        ON d.ID = s.DEVICE_ID AND s.RN=1;
        

        @krokodilko:非常感谢您的帮助。第一个查询有效。修改它以删除垃圾,放置我需要的真实列名(昨天晚上我无法访问数据库)并只获取我需要的数据。

        不幸的是,当我按照你的建议加入这两个表时,我得到了错误:

        ORA-00904: "S"."RN": 无效标识符 00904. 00000 - "%s: 无效标识符"

        如果我删除 s.在 RN 之前,ORA-00904 移回 s.DEVICE_ID。

        【讨论】:

          猜你喜欢
          • 2019-07-15
          • 1970-01-01
          • 1970-01-01
          • 2022-08-15
          • 2021-03-14
          • 2018-03-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多