有没有办法按用户堆叠/分组字符串/文本?
我有数据
USER STATES
1 CA
1 AR
1 IN
2 CA
3 CA
3 NY
4 CA
4 AL
4 SD
4 TX
我需要的是
USER STATES
1 CA / AR / IN
2 CA
3 CA / NY
4 CA / AL / SD / TX
我尝试了交叉连接,然后尝试了另一个交叉连接但数据假脱机。谢谢!
答案 0 :(得分:2)
如果安装了Teradata的XML服务,那么会有一个名为XMLAGG的函数,它会返回类似的结果:CA, AR, IN
SELECT user,
TRIM(TRAILING ',' FROM (XMLAGG(TRIM(states)|| ',' /* optionally ORDER BY ...*/) (VARCHAR(10000))))
FROM tab
GROUP BY 1
顺便说一句,使用递归会导致使用大量的假脱机,因为在返回最后一行之前,所有中间行都保留在假脱机中。
答案 1 :(得分:1)
不幸的是Teradata中没有GROUP_CONCAT
或任何字符串聚合函数(至少没有我知道的),所以实现结果的一种方法是使用递归,因为你不知道每个用户的最大状态值。
对于递归,您应该使用易失性表,因为递归部分中不允许OLAP函数。这是一个未经测试的代码(遗憾的是我无法对其进行测试),因此可能存在一些错误,但是应该给出概念并进行一些故障排除(如果需要)给出预期的结果。
将Volatile Table的定义中的yourtable
替换为您的真实表名。
CREATE VOLATILE TABLE vt AS (
SELECT
user
, states
, ROW_NUMBER() OVER (PARTITION BY user ORDER BY states) AS rn
, COUNT(*) OVER (PARTITION BY user) AS cnt
FROM yourtable
) WITH DATA
UNIQUE PRIMARY INDEX(user, rn)
ON COMMIT PRESERVE ROWS;
WITH RECURSIVE cte (user, list, rn) AS (
SELECT
user
, CAST(states AS VARCHAR(1000)) -- maximum size based on maximum number of rows * length of states
, rn
FROM vt
WHERE rn = cnt -- start with last states row
UNION ALL
SELECT
vt.user
, cte.list || ',' || vt.states
, vt.rn
FROM vt
JOIN cte ON vt.user = cte.user AND vt.rn = cte.rn - 1 -- append a row that is rn-1 of your rows for a given user
)
SELECT user, list
FROM cte
WHERE rn = 1; -- going from last to first, in this condition there should be entire list
此解决方案并不完美 - 它会强制引擎在查询处理期间将临时结果存储在临时区域中。您可能会遇到No more spool space
错误。
答案 2 :(得分:1)
我不是专家,但这应该有用。您可能需要根据您的具体要求对其进行一些修改。希望这有帮助!
CREATE VOLATILE TABLE temp AS (
SELECT
USER
,STATES
,ROW_NUMBER() OVER (PARTITION BY USER ORDER BY STATES) AS rn
FROM yourtable
) WITH DATA PRIMARY INDEX(USER) ON COMMIT PRESERVE ROWS;
WITH RECURSIVE rec_test(US,ST, LVL)
AS
(
SELECT USER,STATES (VARCHAR(10)),1
FROM temp
WHERE rn = 1
UNION ALL
SELECT USER, TRIM(STATES) || ', ' || ST,LVL+1
FROM temp INNER JOIN rec_test
ON USER = US
AND temp.rn = rec_test.lvl+1
)
SELECT US,ST, LVL
FROM rec_test
QUALIFY RANK() OVER(PARTITION BY US ORDER BY LVL DESC) = 1;