SQL算法与三列连接

SQL算法与三列连接,sql,hsqldb,Sql,Hsqldb,我有一个如下所示的模式: +----------+ | tour | +----------+ | id | | name | +----------+ +----------+ | golfer | +----------+ | id | | name | | tour_id | +----------+ +-----------+ | stat | +-----------+ | id | | round

我有一个如下所示的模式:

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

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

+-----------+
| stat      |
+-----------+
| id        |
| round     |
| score     |
| golfer_id |
+-----------+
所以基本上一次高尔夫巡回赛有X个高尔夫球手。一个高尔夫球手将有X个统计数据。统计表中的圆形列只包含数字(1、2、3、4…等等)。它们不一定是一个接一个的,但它们是独一无二的

我现在想找到所有参加“PGA”巡回赛的高尔夫球手,并为每一位球手统计他们在最后两轮的得分。最后两轮基本上是统计表中两个数字最大的高尔夫球手的行。假设高尔夫球手“老虎伍兹”打了第1、3、6和10轮,那么我只想统计他在第6和10轮的得分。另一个要求是,我不想让那些至少打过两轮的高尔夫球手看到


我试过几种方法来让这一切顺利进行,但总是让自己陷入困境。

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

诀窍是在高尔夫球手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,您需要使用
limit1
。对于其他数据库,请使用数据库引擎的特定方式

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

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

将此查询加入tour表以获取PGA巡回赛的高尔夫球手,并将此查询加入stats表以获取最后两轮的得分,这只是一个简单的练习。

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

诀窍是在高尔夫球手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,您需要使用
limit1
。对于其他数据库,请使用数据库引擎的特定方式

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

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

将此查询连接到tour表以获取PGA tour的高尔夫球手,并将此查询连接回stats表以获取最近两轮的得分,这只是一个简单的练习。

HSQLDB 2.1支持横向连接,允许使用任意条件进行此类选择

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

select golfer.name from tour join golfer on (tour.id = tour_id and  tour.name = 'PGA')
然后,您可以根据需要多次加入此表以获得特定分数。下一个示例包括上一轮的得分(仅当该剧已进行一轮时)

在下一个示例中,将使用一个或多个横向连接来包括最后一个但只有一个圆。如果该玩家未打两轮,则该玩家将不会有排:

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

横向联接不需要WHERE子句,因为“WHERE条件”取自当前表前面的from列表中的表。因此,横向表格子查询中的SELECT语句可以使用第一个联接表格中的golfer.id。

HSQLDB 2.1支持横向联接,允许使用任意条件进行此类选择

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

select golfer.name from tour join golfer on (tour.id = tour_id and  tour.name = 'PGA')
然后,您可以根据需要多次加入此表以获得特定分数。下一个示例包括上一轮的得分(仅当该剧已进行一轮时)

在下一个示例中,将使用一个或多个横向连接来包括最后一个但只有一个圆。如果该玩家未打两轮,则该玩家将不会有排:

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

横向联接不需要WHERE子句,因为“WHERE条件”取自当前表前面的from列表中的表。因此,横向表格子查询中的SELECT语句可以使用第一个联接表格中的golfer.id。

@Hogan,谢谢。在有窗口功能之前,这是我多年来一直使用的技巧。它在试图找到目标时非常有效