对选择的一对一明显限制

时间:2014-07-25 21:44:26

标签: sql postgresql

我遇到了类似的问题。有两个表(x值是这样排序的 在增量趋势中!)

表A

    id     x
    1      1
    1      3
    1      4
    1      7

表B

    id     x
    1      2
    1      5

我想加入这两个表:
1)在id和
的平等条件下 2)A的每一行应根据x值的绝对差异仅与一行B匹配,反之亦然(一对一关系)(小差行有 更优先匹配)。

仅基于上面的描述,它不是一个清晰的描述,因为如果在一个表中共享一个共同行的两对行具有相同的差异,则无法确定哪一行首先出现。因此,将A定义为" Main"表中,表A中具有较小行号的行总是先行

演示的预期结果:

    id      A.x     B.x    abs_diff
    1       1       2      1
    1       4       5      1

表格结尾(不应考虑A中的两个额外行,因为一对一规则)

我正在使用PostgreSQL,所以我尝试的是DISTINCT ON,但它无法解决。

    select distinct on (A.x) id,A.x,B.x,abs_diff
    from
    (A join B
    on A.id=B.id)
    order by A.x,greatest(A.x,B.x)-least(A.x,B.x)

你有什么想法,在普通的SQL中似乎很棘手。

2 个答案:

答案 0 :(得分:1)

尝试:

select a.id, a.x as ax, b.x as bx, x.min_abs_diff
  from table_a a
  join table_b b
    on a.id = b.id
  join (select a.id, min(abs(a.x - b.x)) as min_abs_diff
          from table_a a
          join table_b b
            on a.id = b.id
         group by a.id) x
    on x.id = a.id
   and abs(a.x - b.x) = x.min_abs_diff

小提琴:http://sqlfiddle.com/#!15/ab5ae/5/0

虽然它与您的预期输出不匹配,但我认为根据您所描述的内容输出是正确的,因为您可以看到每对在绝对值为1时存在差异。

编辑 - 根据a到b的顺序尝试以下内容:

select *
  from (select a.id,
               a.x as ax,
               b.x as bx,
               x.min_abs_diff,
               row_number() over(partition by a.id, b.x order by a.id, a.x) as rn
          from table_a a
          join table_b b
            on a.id = b.id
          join (select a.id, min(abs(a.x - b.x)) as min_abs_diff
                 from table_a a
                 join table_b b
                   on a.id = b.id
                group by a.id) x
            on x.id = a.id
           and abs(a.x - b.x) = x.min_abs_diff) x
 where x.rn = 1

小提琴:http://sqlfiddle.com/#!15/ab5ae/19/0

答案 1 :(得分:1)

针对您目前模棱两可的问题的一种可能解决方案:

SELECT *
FROM  (
    SELECT id, x AS a, lead(x) OVER (PARTITION BY grp ORDER BY x) AS b
    FROM  (
        SELECT *, count(tbl) OVER (PARTITION BY id ORDER BY x) AS grp
        FROM  (
            SELECT TRUE AS tbl, * FROM table_a
            UNION ALL
            SELECT NULL, * FROM table_b
            ) x
        ) y
    ) z
WHERE  b IS NOT NULL
ORDER  BY 1,2,3;

这样,每个a.x都会被分配下一个更大(或相同)b.x,除非有另一个a.x仍然小于下一个b.x(或同样的。)

为演示案例生成请求的结果。不确定各种含糊不清的案例。

SQL Fiddle.