如何使用标准SQL连接以逗号分隔的行?
假设我们有一个表T1和一个表T2。T1和T2之间存在1:n的关系。我想选择所有T1及其所有T2,每一行对应于T2值串联的T1记录,只使用SQL标准操作 例如: T1=人 T2=受欢迎程度(按年份) 一个人每年都有一定的人气 我想使用SQL标准操作编写一个选择,结果如下:如何使用标准SQL连接以逗号分隔的行?,sql,ansi-sql,Sql,Ansi Sql,假设我们有一个表T1和一个表T2。T1和T2之间存在1:n的关系。我想选择所有T1及其所有T2,每一行对应于T2值串联的T1记录,只使用SQL标准操作 例如: T1=人 T2=受欢迎程度(按年份) 一个人每年都有一定的人气 我想使用SQL标准操作编写一个选择,结果如下: Person.Name Popularity.Value John Smith 1.2,5,4.2 John Doe NULL Jane Smith 8 其中John Smith的受欢迎程度表
Person.Name Popularity.Value
John Smith 1.2,5,4.2
John Doe NULL
Jane Smith 8
其中John Smith的受欢迎程度表中有3条记录,John Doe没有记录,Jane Smith有一条记录,其值为上述值。这可能吗?怎么做
我正在使用Oracle,但希望仅使用标准SQL来完成此操作。根据Oracle中的说明,您可以使用
listag
来实现此目标-
select t1.Person_Name, listagg(t2.Popularity_Value)
within group(order by t2.Popularity_Value)
from t1, t2
where t1.Person_Name = t2.Person_Name (+)
group by t1.Person_Name
我希望这能解决你的问题
但是你在@DavidJashi问题之后的评论。。这不是sql标准,我认为他是正确的。我也同意David的观点,在纯sql语句中无法实现这一点 这里有一种技术,使用递归公共表表达式。不幸的是,我对它的性能没有信心 我确信有一些方法可以改进这段代码,但它表明,仅仅使用SQL标准似乎并不是一种简单的方法来完成类似的事情 就我所见,确实应该有某种
STRINGJOIN
聚合函数,可以与groupby
一起使用。这会让事情变得更容易
此查询假设存在某种连接这两个关系的
PersonID
,但是名称也可以工作
WITH cte (id, Name, Value, ValueCount) AS (
SELECT id,
Name,
CAST(Value AS VARCHAR(MAX)) AS Value,
1 AS ValueCount
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Name) AS id,
Name,
Value
FROM Person AS per
INNER JOIN Popularity AS pop
ON per.PersonID = pop.PersonID
) AS e
WHERE id = 1
UNION ALL
SELECT e.id,
e.Name,
cte.Value + ',' + CAST(e.Value AS VARCHAR(MAX)) AS Value,
cte.ValueCount + 1 AS ValueCount
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Name) AS id,
Name,
Value
FROM Person AS per
INNER JOIN Popularity AS pop
ON per.PersonID = pop.PersonID
) AS e
INNER JOIN cte
ON e.id = cte.id + 1
AND e.Name = cte.Name
)
SELECT p.Name, agg.Value
FROM Person p
LEFT JOIN (
SELECT Name, Value
FROM (
SELECT Name,
Value,
ROW_NUMBER() OVER (PARTITION BY Name ORDER BY ValueCount DESC)AS id
FROM cte
) AS p
WHERE id = 1
) AS agg
ON p.Name = agg.Name
这是一个示例结果:
--------------------------------
| Name | Value |
--------------------------------
| John Smith | 1.2,5,4.2 |
--------------------------------
| John Doe | NULL |
--------------------------------
| Jane Smith | 8 |
--------------------------------
我知道我在聚会上迟到了,但是对于其他可能发现这一点的人来说,我不相信使用纯SQL92就可以做到这一点。在过去的几个月里,我发现NetSuite试图找出哪些Oracle方法可以和哪些Oracle方法不能与他们的ODBC驱动程序一起使用,我发现他们只“支持并保证”SQL92标准
我发现了这一点,因为我需要执行listag()。一旦我发现我只能使用SQL92,我就对历史记录进行了一些挖掘,而在SQL92中根本不支持listag()和递归查询(公共表表达式)
Listag()是在Oracle SQL版本11g第2版(2009–11年前:参考)中添加的,CTE是在Oracle SQL版本9.2(2007–13年前:参考)中添加的
非常令人沮丧的是,在纯SQL92中完全不可能实现这种效果,因此在我提取了大量额外的不必要数据后,我不得不在我的C代码中解决这个问题。非常令人沮丧。不要认为如果不使用特定于供应商的技巧,就可以在纯SQL92中实现它。想要一个只有Oracle的解决方案吗?可能与我想在Oracle中实现这一点,但要使用SQL标准操作。@DavidJashi:不可能通过递归公共表表达式实现吗?这是SQL标准,但我相信是SQL99。它通常比特定于供应商的方法慢得多。此外,这个问题的标题是如何在Oracle中将多行合并到逗号分隔的列表中?这将指定供应商。我没有指定供应商,只是在问题中添加了一个标记,表明我将在Oracle中实现这一点。但在我明确指定的问题中,我希望以一种与技术无关的方式解决这个问题,提到我希望有一个符合SQL标准的解决方案。我已经用Oracle特定的方法解决了这个问题,所以您提到的问题中的答案没有回答这个问题,所以这不是重复的问题。谢谢,这解决了问题,但它不是技术不可知的,因为您不能在任何SQL实现器技术中使用Listag,它不在SQL标准中。例如,如果我以这种方式解决问题,那么我就无法将我的项目迁移到PostgreSQL。这并不是在回答我的问题,但无论如何,我感谢您的尝试。不客气,我再次告诉您,就我所知,在纯SQL中没有可以做的工作。。。但如果您发现任何问题,请同时更新我..目前我有n+1个数据库请求,而不是一个,因为在这种情况下,仅在Oracle中工作的解决方案是不可接受的。沃伊索斯向我们保证他会给出一个解决方案,所以我在等待。同时我也在考虑这个问题,所以也许我会提供一个解决方案。我们会看到。@ LaJaSpPad:我不知道我是否会考虑我发布的“解决方案”,不幸的是,谢谢你,VoiSOS,我会尽快实现你的想法,并让你知道结果。如果它符合SQL标准并且有效,我将接受它。非常感谢。@LajosArpad:请注意性能。如果你实现了它,一定要使用真实的数据集大小进行测试。我刚刚提出了一些类似的想法,编写代码的过程向我展示了编写“数据库不可知”代码是多么毫无意义。即使是像用“from dual”创建测试数据或用“| |”、“+”或“concat”连接字符串这样简单的事情也说明了这是多么困难。太麻烦了@MikeMeyers:我同意——我认为这样的事情在应用程序代码中更容易处理。如果你真的想成为数据库不可知论者,可以使用ORM或其他某种抽象。ORA-32033:不支持的列别名32033。00000-“不支持的列别名”*原因:WITH子句中的列别名尚不受支持*操作:在定义子查询中指定别名,并在第10行“列:10”处重试错误