-- Original data
WITH tbl(ID, COL, op, val) AS (
SELECT 1, 'math', '>=', 75 FROM dual UNION ALL
SELECT 2, 'math', '<=', 82 FROM dual UNION ALL
SELECT 3, 'sci', '=', 72 FROM dual UNION ALL
SELECT 4, 'geo', '>', 45 FROM dual UNION ALL
SELECT 5, 'geo', '<', 50 FROM dual
),
-- Find the ranges based on the col and it's operator
range_tbl(ID, start_val, end_val) AS (
SELECT ID,
CASE op
WHEN '>'
THEN val + 1
ELSE val
END AS start_val,
CASE op
WHEN '>='
THEN (SELECT val
FROM tbl tbl1
WHERE tbl1.COL=tbl.COL
AND op = '<=')
WHEN '>'
THEN (SELECT val-1
FROM tbl tbl1
WHERE tbl1.COL=tbl.COL
AND op = '<')
WHEN '='
THEN val
END AS end_val
FROM tbl
),
-- "Loop" through each range using connect by
nbr_tbl(nbr) AS (
SELECT start_val + (LEVEL-1) AS nbr
FROM range_tbl
WHERE end_val IS NOT NULL
CONNECT BY LEVEL <= (end_val - start_val)+1
AND PRIOR ID = ID
AND PRIOR SYS_GUID() IS NOT NULL
)
-- Now put them into a single row using listagg
SELECT LISTAGG(nbr, ',')
WITHIN GROUP (ORDER BY nbr) AS nbr_list
FROM nbr_tbl
;
SQL> WITH YOUR_TABLE(id, col, op, value) AS
2 (SELECT 1, 'math', '>=', 75 FROM DUAL UNION ALL
3 SELECT 2, 'math', '<=', 82 FROM DUAL UNION ALL
4 SELECT 3, 'sci', '=', 72 FROM DUAL UNION ALL
5 SELECT 4, 'geo', '>', 45 FROM DUAL UNION ALL
6 SELECT 5, 'geo', '<', 50 FROM DUAL)
7 -- YOUR QUERY STARTS FROM HERE
8 SELECT
9 LISTAGG(V.COLUMN_VALUE, ',') WITHIN GROUP( ORDER BY V.COLUMN_VALUE) AS RES
10 FROM (
11 SELECT COL,
12 MIN( CASE WHEN OP IN( '=', '>=') THEN VALUE
13 WHEN OP = '>' THEN VALUE + 1
14 END ) AS MINVAL,
15 MAX( CASE WHEN OP IN( '=', '<=') THEN VALUE
16 WHEN OP = '<' THEN VALUE - 1
17 END ) AS MAXVAL
18 FROM YOUR_TABLE
19 GROUP BY COL) T
20 CROSS JOIN TABLE ( CAST(MULTISET(
21 SELECT T.MINVAL + LEVEL - 1
22 FROM DUAL CONNECT BY LEVEL <= T.MAXVAL - T.MINVAL + 1
23 ) AS SYS.ODCIVARCHAR2LIST) ) V;
RES
---------------------------------------------------
46,47,48,49,72,75,76,77,78,79,80,81,82
SQL>
3条答案
按热度按时间dtcbnfnu1#
知道了!有点复杂,但希望评论能有所帮助。这是一个使用公共表表达式(commontableexpressions,cte)分解成步骤的查询。这证明它是可以做到的,但我强烈建议找到一个更好的方法来解决你的问题。
输出:
mbjcgjjk2#
你想输出范围吗,像这样的?
数学:75,76,77,78,79,80,81,82
科学院:72
地理位置:46,47,48,49
如果是这样的话,单独使用sql是错误的。您可以使用sql在另一个工具(可能是pl/sql)中帮助构建动态表达式。
jbose2ul3#
我想你得去拿
min
以及max
值并按如下方式生成数字: