英文:
Concatenate all varchar values of a column above a row in oracle
问题
I'll provide a translation of the content you provided:
我有一个使用情况,在其中有一列存储一些字符、flg列和一个category列。
根据flg,如果flg为1,则对于第i行,res1应该是第i行上方的行的字符连接(用''+''连接),以及第i行的Column1值。“上方的第i行”意味着SEQNCE<SEQNCE(i)。
如果flg为零,则res1=Column1。对行上方的连接仅限于Category相同的情况,如果Category发生变化(例如,Category=2 Column1='I'是一个新集合),则应从那一行开始连接的过程。
例如,下面是名为'dmy_tbl'的表格:
LISTAGG是一种用于按其他列分组连接字符串的选项,而LAG是用于获取行上方行的选项,我尝试了下面的查询,但没有得到预期的结果。而且我无法决定如何根据category分区。对于这个使用情况,欢迎任何建议。
select column1,catg,flg,SEQNCE,
case when ((flg=1 and res is null) or flg=0) then column1
else column1||'+'||res end as result
from
(select column1,catg,flg,SEQNCE,
case when flg=1 then lag(column1)
over(order by catg,SEQNCE asc) else column1 end as res
FROM dmy_tbl
order by catg,SEQNCE asc);
内部查询中,res列仅获取上面的一行,不确定如何将LISTAGG嵌入到内部查询中以获取所有上面的行。
英文:
I have a use case wherein there is a column which stores some characters, flg column and a category column.
Based on flg, if flg is 1 then for ith row the res1 should be concatenation of characters (concatenated by ''+'') of rows above the ith row and the ith row Column1 value. "Above ith row" meaning SEQNCE<SEQNCE(i).
If flg is zero then res1=Column1. This concatenation of rows above a row is limited only until category is same, if Category changes(eg. Category=2 Column1='I' is a new set) it should start from that row the process of concatenation.
For eg. below is the table named ''dmy_tbl''
LISTAGG is one such option to concatenate strings group by other column & LAG is option for fetching rows above a row, I have tried below query but it does not yield expected result. Also I'm not able to make a decision on how to partition on category. Any suggestion for this use case is highly welcomed.
select column1,catg,flg,SEQNCE,
case when ((flg=1 and res is null) or flg=0) then column1
else column1||'+'||res end as result
from
(select column1,catg,flg,SEQNCE,
case when flg=1 then lag(column1)
over(order by catg,SEQNCE asc) else column1 end as res
FROM dmy_tbl
order by catg,SEQNCE asc);
The inner query, res column is only fetching one row above, not sure on how to fit in LISTAGG in the inner query to fetch all above rows
答案1
得分: 1
你可以使用 MODEL
子句:
选择 列1,
指示器,
序列,
类别,
CASE 指示器
当 0
然后 列1
否则 结果
结束 AS 结果1
从 dmy_tbl
模型
按 (类别) 分区
按 (序列) 维度
度量 (
列1,
指示器,
CAST(NULL AS VARCHAR2(4000)) AS 结果
)
规则 (
结果[1] = 列1[1],
结果[序列>1] = 结果[cv()-1] || '+' || 列1[cv()]
);
对于示例数据:
创建表 dmy_tbl (列1, 指示器, 序列, 类别) 作为
选择 'A', 1, 1, 1 FROM DUAL UNION ALL
选择 'B', 0, 2, 1 FROM DUAL UNION ALL
选择 'C', 0, 3, 1 FROM DUAL UNION ALL
选择 'D', 1, 4, 1 FROM DUAL UNION ALL
选择 'E', 1, 5, 1 FROM DUAL UNION ALL
选择 'F', 1, 6, 1 FROM DUAL UNION ALL
选择 'G', 0, 7, 1 FROM DUAL UNION ALL
选择 'H', 1, 8, 1 FROM DUAL UNION ALL
选择 'I', 1, 1, 2 FROM DUAL UNION ALL
选择 'J', 0, 2, 2 FROM DUAL UNION ALL
选择 'K', 1, 3, 2 FROM DUAL UNION ALL
选择 'L', 1, 4, 2 FROM DUAL;
输出:
列1 | 指示器 | 序列 | 类别 | 结果1 |
---|---|---|---|---|
A | 1 | 1 | 1 | A |
B | 0 | 2 | 1 | B |
C | 0 | 3 | 1 | C |
D | 1 | 4 | 1 | A+B+C+D |
E | 1 | 5 | 1 | A+B+C+D+E |
F | 1 | 6 | 1 | A+B+C+D+E+F |
G | 0 | 7 | 1 | G |
H | 1 | 8 | 1 | A+B+C+D+E+F+G+H |
I | 1 | 1 | 2 | I |
J | 0 | 2 | 2 | J |
K | 1 | 3 | 2 | I+J+K |
L | 1 | 4 | 2 | I+J+K+L |
英文:
You can use a MODEL
clause:
SELECT column1,
indicator,
seqnce,
category,
CASE indicator
WHEN 0
THEN column1
ELSE res
END AS res1
FROM dmy_tbl
MODEL
PARTITION BY (category)
DIMENSION BY (seqnce)
MEASURES (
column1,
indicator,
CAST(NULL AS VARCHAR2(4000)) AS res
)
RULES (
res[1] = column1[1],
res[seqnce>1] = res[cv()-1] || '+' || column1[cv()]
);
Which, for the sample data:
CREATE TABLE dmy_tbl (column1, indicator, seqnce, category) AS
SELECT 'A', 1, 1, 1 FROM DUAL UNION ALL
SELECT 'B', 0, 2, 1 FROM DUAL UNION ALL
SELECT 'C', 0, 3, 1 FROM DUAL UNION ALL
SELECT 'D', 1, 4, 1 FROM DUAL UNION ALL
SELECT 'E', 1, 5, 1 FROM DUAL UNION ALL
SELECT 'F', 1, 6, 1 FROM DUAL UNION ALL
SELECT 'G', 0, 7, 1 FROM DUAL UNION ALL
SELECT 'H', 1, 8, 1 FROM DUAL UNION ALL
SELECT 'I', 1, 1, 2 FROM DUAL UNION ALL
SELECT 'J', 0, 2, 2 FROM DUAL UNION ALL
SELECT 'K', 1, 3, 2 FROM DUAL UNION ALL
SELECT 'L', 1, 4, 2 FROM DUAL;
Outputs:
COLUMN1 | INDICATOR | SEQNCE | CATEGORY | RES1 |
---|---|---|---|---|
A | 1 | 1 | 1 | A |
B | 0 | 2 | 1 | B |
C | 0 | 3 | 1 | C |
D | 1 | 4 | 1 | A+B+C+D |
E | 1 | 5 | 1 | A+B+C+D+E |
F | 1 | 6 | 1 | A+B+C+D+E+F |
G | 0 | 7 | 1 | G |
H | 1 | 8 | 1 | A+B+C+D+E+F+G+H |
I | 1 | 1 | 2 | I |
J | 0 | 2 | 2 | J |
K | 1 | 3 | 2 | I+J+K |
L | 1 | 4 | 2 | I+J+K+L |
答案2
得分: 0
从Oracle 12开始,您可以使用MATCH_RECOGNIZE
和LISTAGG
:
SELECT MAX(CASE rn WHEN 1 THEN column1 END) AS column1,
MAX(CASE rn WHEN 1 THEN indicator END) AS indicator,
MAX(CASE rn WHEN 1 THEN seqnce END) AS seqnce,
category,
LISTAGG(column1, ''+') WITHIN GROUP (ORDER BY column1) AS res1
FROM dmy_tbl
MATCH_RECOGNIZE(
PARTITION BY category
ORDER BY seqnce DESC
MEASURES
COUNT(*) AS rn,
MATCH_NUMBER() AS mn
ALL ROWS PER MATCH
AFTER MATCH SKIP TO NEXT ROW
PATTERN ( zero | one any_row* )
DEFINE
zero AS indicator = 0,
one AS indicator = 1
)
GROUP BY category, mn
ORDER BY category, seqnce;
对于示例数据:
CREATE TABLE dmy_tbl (column1, indicator, seqnce, category) AS
SELECT ''A'', 1, 1, 1 FROM DUAL UNION ALL
SELECT ''B'', 0, 2, 1 FROM DUAL UNION ALL
SELECT ''C'', 0, 3, 1 FROM DUAL UNION ALL
SELECT ''D'', 1, 4, 1 FROM DUAL UNION ALL
SELECT ''E'', 1, 5, 1 FROM DUAL UNION ALL
SELECT ''F'', 1, 6, 1 FROM DUAL UNION ALL
SELECT ''G'', 0, 7, 1 FROM DUAL UNION ALL
SELECT ''H'', 1, 8, 1 FROM DUAL UNION ALL
SELECT ''I'', 1, 1, 2 FROM DUAL UNION ALL
SELECT ''J'', 0, 2, 2 FROM DUAL UNION ALL
SELECT ''K'', 1, 3, 2 FROM DUAL UNION ALL
SELECT ''L'', 1, 4, 2 FROM DUAL;
输出:
COLUMN1 | INDICATOR | SEQNCE | CATEGORY | RES1 |
---|---|---|---|---|
A | 1 | 1 | 1 | A |
B | 0 | 2 | 1 | B |
C | 0 | 3 | 1 | C |
D | 1 | 4 | 1 | A+B+C+D |
E | 1 | 5 | 1 | A+B+C+D+E |
F | 1 | 6 | 1 | A+B+C+D+E+F |
G | 0 | 7 | 1 | G |
H | 1 | 8 | 1 | A+B+C+D+E+F+G+H |
I | 1 | 1 | 2 | I |
J | 0 | 2 | 2 | J |
K | 1 | 3 | 2 | I+J+K |
L | 1 | 4 | 2 | I+J+K+L |
英文:
From Oracle 12, you can use MATCH_RECOGNIZE
and LISTAGG
:
SELECT MAX(CASE rn WHEN 1 THEN column1 END) AS column1,
MAX(CASE rn WHEN 1 THEN indicator END) AS indicator,
MAX(CASE rn WHEN 1 THEN seqnce END) AS seqnce,
category,
LISTAGG(column1, '+') WITHIN GROUP (ORDER BY column1) AS res1
FROM dmy_tbl
MATCH_RECOGNIZE(
PARTITION BY category
ORDER BY seqnce DESC
MEASURES
COUNT(*) AS rn,
MATCH_NUMBER() AS mn
ALL ROWS PER MATCH
AFTER MATCH SKIP TO NEXT ROW
PATTERN ( zero | one any_row* )
DEFINE
zero AS indicator = 0,
one AS indicator = 1
)
GROUP BY category, mn
ORDER BY category, seqnce;
Which, for the sample data:
CREATE TABLE dmy_tbl (column1, indicator, seqnce, category) AS
SELECT 'A', 1, 1, 1 FROM DUAL UNION ALL
SELECT 'B', 0, 2, 1 FROM DUAL UNION ALL
SELECT 'C', 0, 3, 1 FROM DUAL UNION ALL
SELECT 'D', 1, 4, 1 FROM DUAL UNION ALL
SELECT 'E', 1, 5, 1 FROM DUAL UNION ALL
SELECT 'F', 1, 6, 1 FROM DUAL UNION ALL
SELECT 'G', 0, 7, 1 FROM DUAL UNION ALL
SELECT 'H', 1, 8, 1 FROM DUAL UNION ALL
SELECT 'I', 1, 1, 2 FROM DUAL UNION ALL
SELECT 'J', 0, 2, 2 FROM DUAL UNION ALL
SELECT 'K', 1, 3, 2 FROM DUAL UNION ALL
SELECT 'L', 1, 4, 2 FROM DUAL;
Outputs:
COLUMN1 | INDICATOR | SEQNCE | CATEGORY | RES1 |
---|---|---|---|---|
A | 1 | 1 | 1 | A |
B | 0 | 2 | 1 | B |
C | 0 | 3 | 1 | C |
D | 1 | 4 | 1 | A+B+C+D |
E | 1 | 5 | 1 | A+B+C+D+E |
F | 1 | 6 | 1 | A+B+C+D+E+F |
G | 0 | 7 | 1 | G |
H | 1 | 8 | 1 | A+B+C+D+E+F+G+H |
I | 1 | 1 | 2 | I |
J | 0 | 2 | 2 | J |
K | 1 | 3 | 2 | I+J+K |
L | 1 | 4 | 2 | I+J+K+L |
答案3
得分: 0
如果您不关心是否涉及PL/SQL,一个简单的函数可能会完成任务。
SQL> CREATE OR REPLACE FUNCTION f_res (par_category IN NUMBER, par_seqnce NUMBER)
2 RETURN VARCHAR2
3 IS
4 l_row test%ROWTYPE;
5 retval VARCHAR2 (30);
6 BEGIN
7 SELECT *
8 INTO l_row
9 FROM test
10 WHERE category = par_category
11 AND seqnce = par_seqnce;
12
13 IF l_row.flg = 0
14 THEN
15 retval := l_row.column1;
16 ELSE
17 SELECT LISTAGG (column1, '+') WITHIN GROUP (ORDER BY seqnce)
18 INTO retval
19 FROM test
20 WHERE category = par_category
21 AND seqnce <= par_seqnce;
22 END IF;
23
24 RETURN retval;
25 END;
26 /
函数已创建。
测试:
SQL> SELECT t.*, f_res (t.category, t.seqnce) res1
2 FROM test t
3 ORDER BY t.category, t.seqnce;
C SEQNCE FLG CATEGORY RES1
- ---------- ---------- ---------- ------------------------------
A 1 1 1 A
B 2 0 1 B
C 3 0 1 C
D 4 1 1 A+B+C+D
E 5 1 1 A+B+C+D+E
F 6 1 1 A+B+C+D+E+F
G 7 0 1 G
H 8 1 1 A+B+C+D+E+F+G+H
I 1 1 2 I
J 2 0 2 J
K 3 1 2 I+J+K
L 4 1 2 I+J+K+L
12 rows selected.
SQL>
英文:
If you don't care whether PL/SQL is involved, a simple function might do the job.
SQL> CREATE OR REPLACE FUNCTION f_res (par_category IN NUMBER, par_seqnce NUMBER)
2 RETURN VARCHAR2
3 IS
4 l_row test%ROWTYPE;
5 retval VARCHAR2 (30);
6 BEGIN
7 SELECT *
8 INTO l_row
9 FROM test
10 WHERE category = par_category
11 AND seqnce = par_seqnce;
12
13 IF l_row.flg = 0
14 THEN
15 retval := l_row.column1;
16 ELSE
17 SELECT LISTAGG (column1, '+') WITHIN GROUP (ORDER BY seqnce)
18 INTO retval
19 FROM test
20 WHERE category = par_category
21 AND seqnce <= par_seqnce;
22 END IF;
23
24 RETURN retval;
25 END;
26 /
Function created.
Testing:
SQL> SELECT t.*, f_res (t.category, t.seqnce) res1
2 FROM test t
3 ORDER BY t.category, t.seqnce;
C SEQNCE FLG CATEGORY RES1
- ---------- ---------- ---------- ------------------------------
A 1 1 1 A
B 2 0 1 B
C 3 0 1 C
D 4 1 1 A+B+C+D
E 5 1 1 A+B+C+D+E
F 6 1 1 A+B+C+D+E+F
G 7 0 1 G
H 8 1 1 A+B+C+D+E+F+G+H
I 1 1 2 I
J 2 0 2 J
K 3 1 2 I+J+K
L 4 1 2 I+J+K+L
12 rows selected.
SQL>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论