假设我们有一个表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
其中约翰史密斯的受欢迎表中有3条记录,John Doe和Jane Smith没有记录,它们的值是上面表示的值。这可能吗?怎么样?
我正在使用Oracle,但只想使用标准SQL。
答案 0 :(得分:2)
这是一种使用递归公用表表达式的技术。不幸的是,我对它的表现并不自信。
我确信有很多方法可以改进这些代码,但它表明似乎没有一种简单的方法可以使用SQL标准来做这样的事情。
据我所知,确实应该有某种STRINGJOIN
聚合函数与GROUP BY
一起使用。这会让这样的事情变得更容易......
此查询假定某种PersonID
加入了这两种关系,但Name
也会起作用。
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 |
--------------------------------
答案 1 :(得分:1)
根据Oracle中的说法,您可以使用listagg
来实现此目标 -
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语句中无法实现这一点。
答案 2 :(得分:1)
我知道我参加聚会已经超级迟到了,但是对于可能发现这一点的其他人,我不相信使用纯 SQL92 是可能的。正如我在过去几个月与 NetSuite 争吵以试图弄清楚我可以和不能与他们的 ODBC 驱动程序一起使用的 Oracle 方法时发现的那样,我发现他们只“支持和保证”SQL92 标准。
我发现了这一点,因为我需要执行 LISTAGG()。一旦我发现我只能使用 SQL92,我就对历史记录进行了一些挖掘,而 SQL92 根本不支持 LISTAGG() 和递归查询(公共表表达式)。
LISTAGG() 在 Oracle SQL 11g 第 2 版(2009 – 11 年前:参考 https://oracle-base.com/articles/misc/string-aggregation-techniques#listagg)中添加,CTE 在 Oracle SQL 9.2 版中添加(2007 – 13 年前:参考 {{3 }}).
非常郁闷的是,在纯SQL92中完全不可能实现这种效果,所以我不得不在我拉出大量多余的不必要数据后,在我的C#代码中解决了这个问题。非常令人沮丧。