SQL算术并加入三列

时间:2011-03-25 02:01:49

标签: sql hsqldb

我的架构看起来像这样:

+----------+
| tour     |
+----------+
| id       |
| name     |
+----------+

+----------+
| golfer   |
+----------+
| id       |
| name     |
| tour_id  |
+----------+

+-----------+
| stat      |
+-----------+
| id        |
| round     |
| score     |
| golfer_id |
+-----------+

因此,高尔夫之旅基本上有X个高尔夫球手。高尔夫球手将拥有X个数据。统计表中的圆形列只包含数字(1,2,3,4 ......等)。它们不一定是一个接一个,但它们是独一无二的。

我现在想要找到属于“PGA”巡回赛的所有高尔夫球手以及每位高尔夫球手,从最后两轮比赛中得分。最后2轮基本上是具有最大两个数字的高尔夫球手的统计表中的行。因此,假设高尔夫球手“老虎伍兹”已经在第1,3,6和10轮比赛中进行了比赛,那么我只想在第6轮和第10轮比赛中得分。另一个要求是我不想展示现在的高尔夫球手至少参加过两轮比赛。

我已经尝试了几种方法来实现这一目标,但总是陷入困境。

2 个答案:

答案 0 :(得分:2)

如果你只想要最后两轮(强调“两个”),那就有一个简单的伎俩。这个技巧不会扩展到获得两个以上,或者不是最后两个记录。为了在分区中获取任意记录,您必须使用窗口函数,这些函数涉及更多,并且仅在较新版本的主流数据库引擎中受支持。

诀窍是在高尔夫球手id上自我平等加入“stat”表格。通过这种方式,您可以获得任意两轮高尔夫球手的所有组合,包括同一轮的组合:

SELECT s1.round as s1_round, s2.round AS s2_round
FROM stat s1 INNER JOIN stat s2 ON (s1.golfer_id = s2.golfer_id)

然后你排除(通过WHERE子句)具有相同轮次的组合,并确保这些组合始终是第一轮>第二轮。这意味着现在你拥有任意两轮高尔夫球手的所有组合,没有重复:

SELECT s1.round as s1_round, s2.round AS s2_round
FROM stat s1 INNER JOIN stat s2 ON (s1.golfer_id = s2.golfer_id)
WHERE s1.round > s2.round

请注意,如果您只选择特定高尔夫球手的记录并在两个圆形列上排序DESC,则顶行将是该高尔夫球手的最后两轮:

SELECT TOP 1 s1.round as s1_round, s2.round AS s2_round
FROM stat s1 INNER JOIN stat s2 ON (s1.golfer_id = s2.golfer_id)
WHERE s1.round > s2.round
ORDER BY s1.round DESC, s2.round DESC

TOP 1是获取最高行的SQL Server术语。对于MySQL,您需要使用LIMIT 1。对于其他数据库,请使用数据库引擎的特定方式。

然而,在这种情况下,你不能这么做只是因为你需要最后两轮所有高尔夫球手。你必须做更多的连接:

SELECT id,
   (SELECT MAX(s1.round) FROM stat s1 INNER JOIN stat s2 ON (s1.golfer_id = s2.golfer_id)
    WHERE s1.round > s2.round AND s1.golfer_id = golfer.id) AS last_round,
   (SELECT MAX(s2.round) FROM stat s1 INNER JOIN stat s2 ON (s1.golfer_id = s2.golfer_id)
    WHERE s1.round > s2.round AND s1.golfer_id = golfer.id) AS second_to_last_round
FROM golfer

这将为每位高尔夫球手提供最后两轮(两列)。

或者使用双列临时设置加入高尔夫球手表也应该有效:

SELECT golfer.id, MAX(r.s1_round) AS last_round, MAX(r.s2_round) AS second_to_last_round
FROM golfer INNER JOIN 
(
 SELECT s1.golfer_id AS golfer_id, s1.round AS s1_round, s2.round AS s2_round
 FROM stat s1 INNER JOIN stat s2 ON (s1.golfer_id = s2.golfer_id)
 WHERE s1.round > s2.round
) r ON (r.golfer_id = golfer.id)
GROUP BY golfer.id

我将此作为一项简单的练习,将此查询加入巡回赛表以获得PGA巡回赛的高尔夫球手,并将此查询加入统计表以获得最后两轮的分数。

答案 1 :(得分:2)

HSQLDB 2.1支持LATERAL连接,允许使用任意标准进行此类选择。

简单的连接将列出PGA巡回赛中的所有高尔夫球手:

select golfer.name from tour join golfer on (tour.id = tour_id and  tour.name = 'PGA')

然后,您可以根据需要多次加入此表格以获得特定分数。下一个例子包括最后一轮的得分(仅当比赛进行了一轮比赛时)

select golfer.name, firststat.score from tour join golfer on (tour.id = tour_id and  tour.name = 'PGA' ),
 lateral(select * from stat where golfer_id = golfer.id order by round desc limit 1) firststat

在下一个示例中,您使用一个横向连接来包括最后一个但是一个圆。如果玩家没有进行两轮比赛,则该玩家将没有任何行:

select golfer.name, secondstat.score score1, firststat.score score2 from tour join golfer on (tour.id = tour_id and  tour.name = 'PGA' ), 
 lateral(select * from stat where golfer_id = golfer.id order by round desc limit 1 offset 1) secondstat, 
 lateral(select * from stat where golfer_id = golfer.id order by round desc limit 1) firststat

LATERAL连接不需要WHERE子句,因为“where condition”取自当前表之前出现的FROM列表中的表。因此,LATERAL表的子查询中的SELECT语句可以使用第一个连接表中的golfer.id。