有没有类似 max() 函数的方法?

Is there any method like max() function?

我想要select最大值,但如果用户在一列中有多个值,则全部保留

我有一个 table :

create table package (U_id, service, offer,product) as
 select   1, 12345, null, null  from dual union all
select   1, null, 25468, null  from dual union all
select   1, null, null, 23456  from dual union all
select   2, 12345, 58889, null  from dual union all
select   2, 43456, null, null  from dual ;

我试过了

select u_id, max(service), max(offer),max(product) 
from package
group by u_id

但是,对于第二个用户,只从服务中获取了最大数量。

我想得到这样一个table:

u_id service offer product
1 12345 25468 23456
2 123456 58889
2 43456

这可能是一种选择:

示例数据:

SQL> WITH
  2     package (U_id,
  3              service,
  4              offer,
  5              product)
  6     AS
  7        (SELECT 1, 12345, NULL, NULL FROM DUAL
  8         UNION ALL
  9         SELECT 1, NULL, 25468, NULL FROM DUAL
 10         UNION ALL
 11         SELECT 1, NULL, NULL, 23456 FROM DUAL
 12         UNION ALL
 13         SELECT 2, 12345, 58889, NULL FROM DUAL
 14         UNION ALL
 15         SELECT 2, 43456, NULL, NULL FROM DUAL),

查询从这里开始:temp CTE 计算每个 u_id 的不同 service/offer/product 值的数量;然后根据 group by 子句中每个 u_id 的总行数检查它,以便查询“知道”是否按这些列分组

 16     temp
 17     AS
 18        (  SELECT u_id,
 19                  COUNT (*) cnt,
 20                  COUNT (DISTINCT service) cnt_service,
 21                  COUNT (DISTINCT offer) cnt_offer,
 22                  COUNT (DISTINCT product) cnt_product
 23             FROM package
 24         GROUP BY u_id)
 25    SELECT p.u_id,
 26           MAX (p.service) service,
 27           MAX (p.offer) offer,
 28           MAX (p.product) product
 29      FROM package p JOIN temp t ON t.u_id = p.u_id
 30  GROUP BY p.u_id,
 31           CASE
 32              WHEN t.cnt <> t.cnt_service + t.cnt_offer + t.cnt_product
 33              THEN
 34                 p.service || p.offer || p.product
 35              ELSE
 36                 NULL
 37           END
 38  ORDER BY p.u_id;

      U_ID    SERVICE      OFFER    PRODUCT
---------- ---------- ---------- ----------
         1      12345      25468      23456
         2      12345      58889
         2      43456

SQL>

从 Oracle 12 开始,您可以使用分析函数对行进行编号,然后在 LATERAL self-join 中使用条件聚合将值放入正确的行中:

WITH row_counts (
  u_id,
  service,
  offer,
  product,
  rn,
  service_rn,
  offer_rn,
  product_rn,
  num_rows
) AS (
  SELECT u_id,
         service,
         offer,
         product,
         ROW_NUMBER() OVER (PARTITION BY u_id ORDER BY ROWNUM) AS rn,
         NVL2(service,
           ROW_NUMBER() OVER (
             PARTITION BY u_id ORDER BY NVL2(service, ROWNUM, NULL) NULLS LAST
           ),
           NULL
         ) AS service_rn,
         NVL2(offer,
           ROW_NUMBER() OVER (
             PARTITION BY u_id ORDER BY NVL2(offer, ROWNUM, NULL) NULLS LAST
           ),
           NULL
         ) AS offer_rn,
         NVL2(product,
           ROW_NUMBER() OVER (
             PARTITION BY u_id ORDER BY NVL2(product, ROWNUM, NULL) NULLS LAST
           ),
           NULL
         ) AS product_rn,
         GREATEST(
           COUNT(service) OVER (PARTITION BY u_id),
           COUNT(offer)   OVER (PARTITION BY u_id),
           COUNT(product) OVER (PARTITION BY u_id)
         ) AS num_rows
  FROM   package
)
SELECT r.u_id,
       d.service,
       d.offer,
       d.product
FROM   row_counts r
       CROSS JOIN LATERAL (
         SELECT MAX(CASE d.service_rn WHEN r.rn THEN d.service END) AS service,
                MAX(CASE d.offer_rn   WHEN r.rn THEN d.offer   END) AS offer,
                MAX(CASE d.product_rn WHEN r.rn THEN d.product END) AS product
         FROM   row_counts d
         WHERE  r.u_id = d.u_id
       ) d
WHERE  r.rn <= r.num_rows
ORDER BY r.u_id, r.rn;

其中,对于示例数据:

CREATE TABLE package (U_id, service, offer, product) AS
  SELECT 1, 12345, NULL, NULL FROM DUAL UNION ALL
  SELECT 1, NULL, 25468, NULL FROM DUAL UNION ALL
  SELECT 1, NULL, NULL, 23456 FROM DUAL UNION ALL
  SELECT 2, 12345, 58889, NULL FROM DUAL UNION ALL
  SELECT 2, 43456, NULL, NULL FROM DUAL;

输出:

U_ID SERVICE OFFER PRODUCT
1 12345 25468 23456
2 12345 58889 null
2 43456 null null

db<>fiddle here


在 Oracle 11 中,您可以使用:

WITH row_counts (
  u_id,
  service,
  offer,
  product,
  rn,
  service_rn,
  offer_rn,
  product_rn,
  num_rows
) AS (
  SELECT u_id,
         service,
         offer,
         product,
         ROW_NUMBER() OVER (PARTITION BY u_id ORDER BY ROWNUM) AS rn,
         NVL2(service,
           ROW_NUMBER() OVER (
             PARTITION BY u_id ORDER BY NVL2(service, ROWNUM, NULL) NULLS LAST
           ),
           NULL
         ) AS service_rn,
         NVL2(offer,
           ROW_NUMBER() OVER (
             PARTITION BY u_id ORDER BY NVL2(offer, ROWNUM, NULL) NULLS LAST
           ),
           NULL
         ) AS offer_rn,
         NVL2(product,
           ROW_NUMBER() OVER (
             PARTITION BY u_id ORDER BY NVL2(product, ROWNUM, NULL) NULLS LAST
           ),
           NULL
         ) AS product_rn,
         GREATEST(
           COUNT(service) OVER (PARTITION BY u_id),
           COUNT(offer)   OVER (PARTITION BY u_id),
           COUNT(product) OVER (PARTITION BY u_id)
         ) AS num_rows
  FROM   package
)
SELECT r.u_id,
       r.rn,
       MAX(CASE d.service_rn WHEN r.rn THEN d.service END) AS service,
       MAX(CASE d.offer_rn   WHEN r.rn THEN d.offer   END) AS offer,
       MAX(CASE d.product_rn WHEN r.rn THEN d.product END) AS product
FROM   row_counts r
       INNER JOIN row_counts d
       ON r.u_id = d.u_id
WHERE  r.rn <= r.num_rows
GROUP BY r.u_id, r.rn
ORDER BY r.u_id, r.rn

输出:

U_ID RN SERVICE OFFER PRODUCT
1 1 12345 25468 23456
2 1 12345 58889 null
2 2 43456 null null

db<>fiddle here