繁体   English   中英

是否可以左联接两个表并让右表为每行提供不超过一次?

[英]Is it possible to left join two tables and have the right table supply each row no more than once?

给定此表结构:

Table A
ID    AGE    EDUCATION
1     23     3
2     25     6
3     22     5

Table B
ID    AGE    EDUCATION
1     26     4
2     24     6
3     21     3

我想找到两个表之间的所有匹配,其中年龄在2岁以下,教育程度在2岁以下。但是,我不想从TableB中选择任何行超过一次。 B中的每一行应选择0或1次,A中的每一行应选择一次或多次(标准左联接)。

SELECT *
FROM TableA as A LEFT JOIN TableB as B ON 
    abs(A.age - B.age) <= 2 AND 
    abs(A.education - B.education) <= 2

A.ID    A.AGE    A.EDUCATION    B.ID    B.AGE   B.EDUCATION
1       23       3              3       21      3
2       25       6              1       26      4
2       25       6              2       24      6
3       22       5              2       24      6
3       22       5              3       21      3

如您所见,与整个结果集相比,输出中的最后两行具有重复的B.ID 2和3。 我希望这些行作为A.ID = 3的单个空匹配返回,因为它们都与先前的A值匹配。

所需的输出:

(请注意,对于A.ID = 3,B中没有匹配项,因为B中的所有行均已连接到A中的行。)

A.ID    A.AGE    A.EDUCATION    B.ID    B.AGE   B.EDUCATION
1       23       3              3       21      3
2       25       6              1       26      4
2       25       6              2       24      6
3       22       5              null    null    null

我可以用一个简短的程序来做到这一点,但是我想使用SQL查询来解决该问题,因为它不适合我,而且我再也不会看到数据或操作环境。

有任何想法吗? 谢谢

正如@Joel Coehoorn先前所说,必须有一种机制可以选择从输出中滤除哪些对(a,b)与相同(b)。 SQL不能很好地允许您在多个匹配项时选择ONE行,因此需要创建数据透视查询,在其中过滤掉不需要的记录。 在这种情况下,可以通过将B的所有匹配ID减小为最小(或最大,这并不重要)来进行过滤,使用可以从集合中返回一个值的任何函数,即min()和max ()最方便使用。 一旦将结果简化为知道所关心的(a,b)对,然后针对该结果进行联接,以提取其余表数据。

select a.id a_id, a.age a_age, a.education a_e,
b.id b_id, b.age b_age, b.education b_e
from a left join
(
SELECT   
  a.id a_id, min(b.id) b_id from a,b where 
  abs(A.age - B.age) <= 2 AND 
  abs(A.education - B.education) <= 2
  group by a.id
) g on a.id = g.a_id
left join b on b.id = g.b_id;

据我所知,使用简单的select语句和联接是不可能实现这样的事情的,因为您需要知道已经选择了什么才能消除重复项。

但是,您可以尝试一些类似的方法:

DECLARE @JoinResults TABLE
(A_ID INT, A_Age INT, A_Education INT, B_ID INT, B_Age INT, B_Education INT)

INSERT INTO @JoinResults (A_ID, A_Age, A_Education)
SELECT ID, AGE, EDUCATION
FROM TableA

DECLARE @i INT
SET @i = 1
--Assume that A_ID is incremental and no values missed
WHILE (@i < (SELECT Max(A_ID) FROM @JoinResults
BEGIN
    UPDATE @JoinResult
    SET B_ID = SQ.ID,
        B_Age = SQ.AGE,
        B_Education = SQ.Education
    FROM (
        SELECT ID, AGE, EDUCATION
        FROM TableB b
        WHERE (
            abs((SELECT A_Age FROM @JoinResult WHERE A_Id = @i) - AGE) <=2
            AND abs((SELECT A_Education FROM @JoinResult WHERE A_Id = @i) - EDUCATION) <=2
        ) AND (SELECT B_ID FROM @JoinResults WHERE B_ID = b.id) IS NULL
    ) AS SQ 

    SET @i = @i + 1
END

SELECT @JoinResults

注意:我目前无权访问数据库,因此未经测试,因此我厌倦了2个潜在问题

  1. 我不确定如果没有结果,更新将如何反应
  2. 我不确定IS NULL检查是否正确以消除重复项。

如果确实出现这些问题,请告诉我,我可以帮助您进行故障排除。

在SQL Server中,可以使用CROSS APPLY语法:

SELECT
    a.id, a.age, a.education, 
    b.id AS b_id, b.age AS b_age, b.education AS b_education
FROM tableB AS b
  CROSS APPLY
    ( SELECT TOP (1) a.*
      FROM tableA AS a
      WHERE ABS(a.age - b.age) <= 2
        AND ABS(a.education - b.education) <= 2
      ORDER BY a.id                                    -- your choice here
    ) AS a ;

根据您在子查询中选择的顺序,将选择来自tableA不同行。

编辑 (在更新之后):但是,上面的查询将不会显示A中没有匹配的行,甚至不会选择B中没有匹配的行。


也可以使用窗口函数来完成,但是Access没有它们。 这是我认为可以在Access中使用的查询:

SELECT
    a.id, a.age, a.education,
    s.id AS s_id, s.age AS b_age, s.education AS b_education
FROM tableB AS a
  LEFT JOIN
    ( SELECT
          b.id, b.age, b.education, MIN(a.id) AS a_id
      FROM tableB AS b
        JOIN tableA AS a
          ON  ABS(a.age - b.age) <= 2
          AND ABS(a.education - b.education) <= 2
      GROUP BY b.id, b.age, b.education
    ) AS s
    ON a.id = s.a_id ;

我不确定Access是否允许这种子查询,但是如果不允许,则可以将其定义为“查询”,然后在另一个查询中使用它。

使用SELECT DISTINCT

SELECT DISTINCT A.id, A.age, A.education, B.age, B.education 
FROM TableA as A LEFT JOIN TableB as B ON 
    abs(A.age - B.age) <= 2 AND 
    abs(A.education - B.education) <= 2

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM