SQL SD:识别两队之间最近的共同对手

时间:2015-10-02 05:33:58

标签: sql oracle

我需要一些帮助来编写一个相当复杂的Oracle SQL查询。

我有一个表格,其中包含两个团队之间玩的游戏列表,其中包含以下列:

  1. Game Date(约会)
  2. Home Team(varchar2(26)),
  3. Opposition Team(varchar2(26)),
  4. Score Difference(数字(38))
  5. 我还创建了一个索引,它只是每个游戏(表格中的每一行)的唯一ID,称为索引'。

    比赛中约有30支球队,已经参加了超过5000场比赛。

    对于每场比赛(每排一场),我希望能够确定第三支球队(称为共享对手),这是由主队和反对队共享的最近(以天为单位)对手。然后我想计算这些历史比赛的两场比赛(主队和共同对手和反对队与共有对手)的得分差异与当前比赛的详细信息(主队和反对队之间)

    到目前为止我的尝试看起来像这样

    SELECT 
      A.GAME_DATE,
      A.GAME_NUMBER,
      A.INDEXING,
      A.HOME_TEAM,
      A.OPP_TEAM,
      B.OPP_TEAM AS SHARED_OPP,
      B.SCORE_DIFF AS OPP_SCORE_DIFF,
      C.SCORE_DIFF AS HOME_SCORE_DIFF,
      MIN((A.GAME_DATE - B.GAME_DATE)+ (A.GAME_DATE - C.GAME_DATE) + ABS(B.GAME_DATE - C.GAME_DATE)) AS TOTAL_DATE_DIFF
    
    FROM
    TEAM_SUMMARY_1 A
    LEFT JOIN TEAM_SUMMARY_1 B ON A.OPP_TEAM = B.HOME_TEAM
    LEFT JOIN TEAM_SUMMARY_1 C ON A.HOME_TEAM = C.HOME_TEAM
    WHERE 
    B.OPP_TEAM <> A.HOME_TEAM AND
    A.OPP_TEAM <> C.OPP_TEAM AND
    B.OPP_TEAM = C.OPP_TEAM AND
    ABS(B.GAME_DATE - C.GAME_DATE) < 5 AND
    A.GAME_DATE - B.GAME_DATE < 20 AND
    A.GAME_DATE - B.GAME_DATE > 0 AND 
    A.GAME_DATE - C.GAME_DATE < 20 AND
    A.GAME_DATE - C.GAME_DATE > 0 
    GROUP BY
      A.GAME_DATE,
      A.GAME_NUMBER,
      A.INDEXING,
      A.HOME_TEAM,
      A.OPP_TEAM,
      B.OPP_TEAM,
      B.SCORE_DIFF,
      C.SCORE_DIFF
    ORDER BY
      A.GAME_DATE,
      A.HOME_TEAM,
      A.OPP_TEAM
    

    此代码确实以某种方式返回我之后的内容,但应用于总日期差异的MIN不起作用。

    如果我必须分多步执行此操作,我不介意,但此刻我似乎无法将这个过程概念化。任何帮助,将不胜感激。

2 个答案:

答案 0 :(得分:0)

看看这个并将相同的想法应用到你的表结构中。

使用的表格,分数可以是正数或负数,或者是0表示平局。

CREATE TABLE dbo.Game
(
 PlayDate DATETIME,
 HomeTeam INT,
 OpposingTeam INT,
 Score INT
)

使用查询

WITH GAME AS
(
    SELECT  ROW_NUMBER() OVER (ORDER BY G1.PlayDate) I, * FROM dbo.Games G1
)
, SHARED AS
(
    SELECT 
    G.I, 
    G.HomeTeam, 
    G.OpposingTeam, 
    H.HomeTeam AS H, 
    H.OpposingTeam AS H2, 
    H.I AS HI, 
    ROW_NUMBER() OVER (PARTITION BY G.I ORDER BY H.I DESC) AS A
    FROM GAME G
    LEFT JOIN GAME H ON 
        (G.OpposingTeam = H.OpposingTeam OR G.OpposingTeam = H.HomeTeam) 
        AND G.HomeTeam <> H.HomeTeam 
        AND G.HomeTeam <> H.OpposingTeam
    WHERE G.I > H.I
)

SELECT G.*, H.HI 
FROM GAME G
LEFT JOIN SHARED H ON G.I = H.I
WHERE A = 1 OR A IS NULL
ORDER BY G.I

基本G.I id是任何一款游戏。 H.HI是与共享apponent匹配的游戏。你可以从SHARED CTE获得你想要的任何领域,如共享游戏的得分,如果共享对手在主场或对方球队等等。其中一些可以稍微成一点但它应该有效。

没有共享对手的游戏出现H为空

测试数据

INSERT [dbo].[Games] ([PlayDate], [HomeTeam], [OpposingTeam], [Score]) VALUES (CAST(N'2015-01-01 00:00:00.000' AS DateTime), 1, 2, 5)
INSERT [dbo].[Games] ([PlayDate], [HomeTeam], [OpposingTeam], [Score]) VALUES (CAST(N'2015-01-04 00:00:00.000' AS DateTime), 1, 2, 10)
INSERT [dbo].[Games] ([PlayDate], [HomeTeam], [OpposingTeam], [Score]) VALUES (CAST(N'2015-01-10 00:00:00.000' AS DateTime), 1, 2, -3)
INSERT [dbo].[Games] ([PlayDate], [HomeTeam], [OpposingTeam], [Score]) VALUES (CAST(N'2015-01-07 00:00:00.000' AS DateTime), 3, 2, -5)
INSERT [dbo].[Games] ([PlayDate], [HomeTeam], [OpposingTeam], [Score]) VALUES (CAST(N'2015-01-13 00:00:00.000' AS DateTime), 2, 3, -8)
INSERT [dbo].[Games] ([PlayDate], [HomeTeam], [OpposingTeam], [Score]) VALUES (CAST(N'2015-01-04 00:00:00.000' AS DateTime), 2, 1, -8)
INSERT [dbo].[Games] ([PlayDate], [HomeTeam], [OpposingTeam], [Score]) VALUES (CAST(N'2015-01-15 00:00:00.000' AS DateTime), 3, 1, 4)
INSERT [dbo].[Games] ([PlayDate], [HomeTeam], [OpposingTeam], [Score]) VALUES (CAST(N'2015-01-20 00:00:00.000' AS DateTime), 3, 2, 9)
INSERT [dbo].[Games] ([PlayDate], [HomeTeam], [OpposingTeam], [Score]) VALUES (CAST(N'2015-01-24 00:00:00.000' AS DateTime), 1, 3, -15)

答案 1 :(得分:0)

日期逻辑略有不同,但避免了日期的减法:

        -- CTE to exchange home and guest teams.
WITH dup AS (
        SELECT team_home AS one
                , team_guest AS two
                , match_date AS match_date
        FROM matches
        UNION ALL
        SELECT team_guest AS one
                , team_home AS two
                , match_date AS match_date
        FROM matches
        )
SELECT m0.*
        , p1.two AS onetwo, p1.match_date AS onedate
        , p2.two AS twotwo, p2.match_date AS twodate
FROM matches m0
        -- all other previous matches for home player
JOIN dup p1 ON p1.one = m0.team_home AND p1.two <> m0.team_guest AND p1.match_date < m0.match_date
        -- all other previous matches for guest player
JOIN dup p2 ON p2.one = m0.team_guest AND p2.two <> m0.team_home AND p2.match_date < m0.match_date AND p1.two = p2.two
WHERE 1=1
        -- suppres older other matches, retaining only the most recent one.
AND NOT EXISTS ( SELECT 1
                FROM dup px
                JOIN dup py ON py.two = px.two
                WHERE px.one = p1.one AND py.one = p2.one
                AND px.match_date < m0.match_date AND (px.match_date > p1.match_date OR px.match_date > p2.match_date)
                AND py.match_date < m0.match_date AND (py.match_date > p2.match_date OR py.match_date > p1.match_date)
                )
ORDER BY
        m0.team_home
        , m0.match_date
        , p1.match_date DESC, p2.match_date DESC
         ;