使用group by选择上一个匹配值的SQL连接

时间:2017-07-06 08:51:47

标签: sql apache-spark-sql

我想在一个与第一个上一个记录匹配的密钥上加入2个表。

我有一个查询来执行此操作。但是,我还想在每个表的结果中包含一列。这迫使我在Group By属性中包含这两个列,这将返回重复的结果。

我使用的查询与此类似(礼貌:stackoverflow):

SELECT t1.frame as frame1,
    t1.string as string1,
    max(t2.frame) as frame2,
    t2.string as string2
    FROM t1 
    JOIN t2 
    ON t2.frame < t1.frame and 
    t1.key=t2.key
    GROUP BY t1.frame, t2.frame, t1.string, t2.string
    ORDER BY t2.frame

我看到的(问题)输出是:

frame1, string1, frame2, string2 
51      text1     6       text2   
107253  text3     6       text2

如何在我的结果中包含string2,以便我不想按其分组,但只包含相应frame2的值?

我尝试在sqlfiddle.com上进行设置,以便于尝试。我填充了一些虚拟数据但是这里连同这个问题,我还看到另一个问题,即它也返回结果,其中frame2 = 2。这不是预期的,因为它应始终匹配frame = 6。我想这可能是字符串分组的副作用?

Link to sqlfiddle example

这里我希望输出只能是1条记录:

frame1,string1,frame2,string2
51      text1    6     text2

我在Spark SQL上这样做,但这应该是一个通用的SQL问题。 感谢。

编辑: 我的数据由传入的数据包组成,我希望将数据包与之前的最新数据包匹配,该数据包具有匹配的ID。例如,

Table t2:
    frame#1:Key=a,Text=abc
    frame#2:Key=a,Text=def
    frame#3:Key=b,Text=efg
    frame#5:Key=c,Text=xyz

Table t1:
    frame#4:Key=a,Text=pqr
    frame#6:Key=c,Text=mno

所以在这里,对于来自t1的帧#4,我希望将它与来自t2的帧匹配,并且具有相同的键。因此它应该与帧#2匹配(不是帧#3 coz键是不同的而不是帧#1因为帧#2是更新的)。同样,帧#6应与帧#5匹配。

希望现在很清楚。

3 个答案:

答案 0 :(得分:1)

SELECT A.*, t1.string AS string1, t2.string AS string2
FROM
(SELECT t1.frame AS frame1, MAX(t2.frame) AS frame2
FROM t1
INNER JOIN t2 ON t1.key=t2.key AND t2.frame< t1.frame
GROUP BY t1.frame
) A
INNER JOIN t1 ON A.frame1=t1.frame
INNER JOIN t2 ON A.frame2=t2.frame;

输出:

    frame1  frame2  string1 string2
1   51      6       text13  text17
2   107253  106999  text25  text39

答案 1 :(得分:0)

这个查询将表格剥离为“只是最新的行”,其中“latest”被定义为“具有键列的最高int值”。

这就是row_number()over()函数的作用;为行分配一个递增的数字,每当密钥更改时重新启动它,具有相同密钥的行按帧递减排序,因此最新的总是rownumber 1

SELECT 
    a.frame as frame1,
    a.string as string1,
    b.frame as frame2  
FROM 
  (SELECT 
   frame, 
   key, 
   string, 
   row_number() over(partition by key order by frame desc) as rown
   from t1
  ) a 
  INNER JOIN 
  (SELECT 
   frame, 
   key, 
   string, 
   row_number() over(partition by key order by frame desc) as rown
   from t2
  ) b
  ON a.rown = 1 and a.key = b.key and b.rown=1

如果您需要更改“最新”的定义,请将顺序更改为升序(它将给出最低的帧数)

如果按照我的评论你的“第一个上一个”的定义不同,即你想要最新的行,(其中一个更高的键号是“更晚”)然后在ON子句中使它rown = 2,并使排序是按键降序

(如果您只是自己运行子查询,它可能对您有帮助,然后查看数据并说“我想要的行总是有一个 rown 的X”)

更新

我怀疑你最近的更新中你希望ON子句在rown = 2的地方可能是你的一个表,如果不是另一个。因为我不清楚你的哪一个表是“落后”,所以你必须在sqlfiddle中编辑上面的答案。这是一个产生你请求的输出的版本

SELECT 
    a.frame as frame1,
    a.string as string1,
    b.frame as frame2,
    b.string 
FROM 
  (SELECT 
   frame, 
   key, 
   string, 
   row_number() over(partition by key order by frame desc) as rown
   from t1
  ) a 
  INNER JOIN 
  (SELECT 
   frame, 
   key, 
   string, 
   row_number() over(partition by key order by frame desc) as rown
   from t2
  ) b
  ON a.rown = 2 and a.key = b.key and b.rown=1

您可能希望在较大的数据集上进行测试

答案 2 :(得分:0)

http://sqlfiddle.com/#!17/47c11/2

select distinct on (t.frame1, t.key1, t.string1)
    t.* 
from
    (select 
        t1.frame frame1, t1.key key1, t1.string string1, t2.frame frame2, t2.key key2, t2.string string2
    from 
         t1 
    join 
         t2 
    on 
         t1.key=t2.key
         and t1.frame > t2.frame
    order by 
         t2.frame desc) t