条件JOIN产生两行

时间:2013-03-18 14:58:14

标签: sql sqlite

我正在尝试加入两个这样的表:

表A

A1, A2, A3
A, 1, 35
A, 1, 70
A, 1, 105

表B

B1,B2, B3
B, 1, 30
C, 1, 32
D, 1, 40
E, 1, 55
F, 1, 60
G, 1, 77
H, 1, 80

预期结果如下:

A, 1, 35, C, 32
A, 1, 70, F, 60
A, 1, 105, H, 80

也就是说,对于表A中的每一行,我想从表B中选择一行,它应该是值B3较小但最接近A3值的行。

到目前为止,我已尝试过以下查询:

SELECT A1, A2, A3, B1, B3 FROM A JOIN (SELECT B1, B2, B3 FROM B ORDER BY B2, B3 DESC) AS A ON A.A2 = B.B2 AND A.B3 < A.A3

但是,这会产生如下表格:

A, 1, 35, B, 30
A, 1, 35, C, 32
A, 1, 70, B, 30
A, 1, 70, C, 32
A, 1, 70, D, 40
A, 1, 70, E, 55

等等。我还尝试在内部SELECT中添加LIMIT 1,但这不会产生任何结果。如果我自己运行内部查询(使用LIMIT 1),我会得到预期的结果。如何更改查询以生成所需结果?我目前正在使用sqlite,但想以可移植到其他DBMS的方式编写它。

3 个答案:

答案 0 :(得分:1)

尝试以下查询:

SELECT 
  a.A1,
  a.A2, 
  a.A3,
  (
    SELECT b.B3
    FROM TableB AS b
    ORDER BY ABS(a.A3 - b.B3)
    LIMIT 1
  ) AS x
FROM TableA AS a;

SQL Fiddle

SQL Fiddle不会让我使用sqlite,因为我的浏览器不支持它,所以我希望这适合你。

编辑:这实际上应该为您提供最接近的值。 77接近70而不是60 ......但我不知道这是不是你想要的。

答案 1 :(得分:1)

如果您只需要初始表中的一行,那么您可以考虑在select子句中使用子查询:

select a.*,
       (select b3
        from TableB b
        where b.b3 <= a.a3
        order by b3 desc
        limit 1
       ) as b3
from TableA a

子查询本身称为“相关子查询”,因为where子句引用内部表(b)和外部表(a)。它按b3对表b的结果进行排序,过滤掉除每行中小于或等于a.a3的所有值。 limit 1返回单个值,因为排序是最接近的值小于或等于a.a3中的值。

您的问题是最接近的值,但示例结果的最大值小于或等于。

答案 2 :(得分:0)

我没有SQLite可用,但以下工作在SQL Server中;你应该可以用LIMIT替换TOP。

只要您指定TOP 1,您就应该能够从select中的嵌套查询中获取它:

select *, 
   (select top 1 B3 
    from B 
    where B3 <= A3
    order by B3 desc)
from A

编辑:要从B添加额外列,需要将上述查询嵌套到子查询中:

select t.*, B.B1 from (
select *, 
   (select top 1 B3 
    from B 
    where B3 <= A3
    order by B3 desc) as B3
from A
) as t join B on B.B3 = t.B3