Teradata SQL 每个用户堆栈行
Teradata SQL stack rows per user
有没有办法 stack/group string/text 每个用户?
我有数据
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
我尝试了交叉连接,然后又尝试了另一个交叉连接,但是数据假脱机。谢谢!
不幸的是,Teradata 中没有 GROUP_CONCAT
或任何字符串聚合函数(至少我知道 none),因此实现结果的一种方法是使用递归,因为您不知道每个用户的状态最大值。
对于递归,您应该使用 Volatile Table,因为递归部分不允许使用 OLAP 函数。这是一个未经测试的代码(不幸的是我没有办法测试它),所以可能有几个错误,但应该给你概念和一些故障排除(如果需要)给你预期的结果。
将 Volatile Table 定义中的 yourtable
替换为您的真实 table 名称。
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
错误。
如果安装了 Teradata 的 XML-服务,则有一个名为 XMLAGG 的函数,returns 类似的结果:CA, AR, IN
SELECT user,
TRIM(TRAILING ',' FROM (XMLAGG(TRIM(states)|| ',' /* optionally ORDER BY ...*/) (VARCHAR(10000))))
FROM tab
GROUP BY 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;
有没有办法 stack/group string/text 每个用户?
我有数据
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
我尝试了交叉连接,然后又尝试了另一个交叉连接,但是数据假脱机。谢谢!
不幸的是,Teradata 中没有 GROUP_CONCAT
或任何字符串聚合函数(至少我知道 none),因此实现结果的一种方法是使用递归,因为您不知道每个用户的状态最大值。
对于递归,您应该使用 Volatile Table,因为递归部分不允许使用 OLAP 函数。这是一个未经测试的代码(不幸的是我没有办法测试它),所以可能有几个错误,但应该给你概念和一些故障排除(如果需要)给你预期的结果。
将 Volatile Table 定义中的 yourtable
替换为您的真实 table 名称。
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
错误。
如果安装了 Teradata 的 XML-服务,则有一个名为 XMLAGG 的函数,returns 类似的结果:CA, AR, IN
SELECT user,
TRIM(TRAILING ',' FROM (XMLAGG(TRIM(states)|| ',' /* optionally ORDER BY ...*/) (VARCHAR(10000))))
FROM tab
GROUP BY 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;