有没有类似 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
我想要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