SQL如何使用同一列中的值匹配2个表

Posted

技术标签:

【中文标题】SQL如何使用同一列中的值匹配2个表【英文标题】:SQL How to match 2 tables using between values in the same column 【发布时间】:2014-12-03 11:42:11 【问题描述】:

我正在努力从表 A 中选择位于表 B 中同一列中的值之间的记录。请在此处查看这些表的基本结构:

表 A

Id   Depth           Comment         
1    150            Status is good
2    215            Status is good
3    330            Status is bad

表 B

    Id   Depth          Material        
    1    130            Hard
    2    200            Soft
    3    220            Very Hard
    4    280            Very Hard
    5    350            Soft

所以,我要做的是从表 A 中选择高于表 B 中深度但低于下一个值(在同一列中的值之间的范围内)的所有值。深度和显示评论和材料。我期待的结果是:

    Depth  Comment          Material         
    150    Status is good   Hard
    215    Status is good   Soft
    330    Status is bad    Very Hard

任何帮助将不胜感激,谢谢!

【问题讨论】:

您使用的是什么数据库?请相应地标记问题。 表之间的IDS是否相关?您希望在输出中显示哪些表格深度? 您好,所有数据都在 Oracle 数据库中,但我已将它们链接到 MS Access 2013 中,并且将来会是 mysql。两个表都有 2 个公共 ID(ID1 和 ID2),但深度不必从一个表匹配到另一个表。我感兴趣的深度位于表 A 中,但是当表 A.depth 在表 B 的范围内时,我想从表 B 中检索值。 【参考方案1】:

您可以为此使用相关子查询。确切的语法取决于数据库,但它们都很简单。这是 ANSI 标准语法:

select a.*,
       (select material
        from b
        where a.depth >= b.depth
        order by b.depth desc
        fetch first 1 row only
       ) as material
from a;

根据数据库,fetch first 1 row only 可能是 limit 1,也可能是 select top 1,或者完全是其他东西。

编辑:

在 MySQL 中,你会这样做:

select a.*,
       (select material
        from b
        where a.depth >= b.depth
        order by b.depth desc
        limit 1
       ) as material
from a;

在 MS Access 中:

select a.*,
       (select top 1 material
        from b
        where a.depth >= b.depth
        order by b.depth desc, b.id
       ) as material
from a;

在 Oracle 12g 中,上述工作。在其他版本中,它稍微复杂一些:

select a.*,
       (select distinct first_value(material) over (order by b.depth desc)
        from b
        where a.depth >= b.depth
       ) as material
from a;

【讨论】:

@JaviGonzalez 。 . .您不接受答案有什么原因吗?【参考方案2】:

假设 ID 是相关的,并且您希望从 TableA 中查看 id 的深度

SELECT a.Depth, a.Comment, b.Material
FROM Tablea a
INNER JOIN Tableb b ON a.ID = b.ID
WHERE a.Depth > b.Depth

【讨论】:

表之间有2个ID相关,但两个数据库中的深度不需要匹配。 b 中有数千个深度高于 a,所以我很遗憾地说这个解决方案不起作用,因为我只想在 b 的范围内定位 a.depth。【参考方案3】:

以下将在 Oracle 上按原样执行。注释掉“from dual”并将“Comment”更改为 [Comment],它也会在 SQL Server 上执行。它只提供您显示的输出。它甚至可以在 MySql 中执行,但您必须将数据存储在实际表中,而不是使用 CTE。

with
TableA( Id, Depth, "Comment" )as(
  select  1, 150, 'Status is good' from dual
  union all
  select  2, 215, 'Status is good' from dual
  union all
  select  3, 330, 'Status is bad' from dual
),
TableB( Id, Depth, Material )as(
  select  1,    130,            'Hard' from dual
  union all
  select  2,    200,            'Soft' from dual
  union all
  select  3,    220,            'Very Hard' from dual
  union all
  select  4,    280,            'Very Hard' from dual
  union all
  select  5,    350,            'Soft' from dual
)
select  a.Depth, a."Comment", b.Material
from  TableA  a
join  TableB  b
  on  b.Depth =(
        select  Max( Depth )
        from    TableB
        where   Depth <= a.Depth );

诀窍是将 TableB 的每一行与 TableB 中最大深度值小于或等于 TableA 行的深度值的行连接起来。不要让子查询抛出你。假设 Depth 被索引,这与几乎任何其他方法一样好或更好。但是如果 TableB 像你展示的那样小,它无论如何都会被读入缓存。

【讨论】:

感谢您的回答。这里的问题是两个表中都有数千个深度并且没有被索引,所以这个例子不适用,因为我需要一种方法来评估不仅是现有的深度,而且是未来的深度。 我不知道你所说的“未来”是什么意思。如果通过添加新条目(“Durable”、“Very Durable”等)或更改现有阈值来更改 TableB,查询仍然可以正常工作。当我在这里时,你能解释一下深度值是如何工作的吗?你从一个低值(硬)开始,然后是一个更大的值(软),然后更高的值(非常硬)到所有值的最大值(软)。那么为什么 349 非常硬而 350 会很软呢?

以上是关于SQL如何使用同一列中的值匹配2个表的主要内容,如果未能解决你的问题,请参考以下文章

当同一列中的值不匹配但不同列重复时将返回结果的 SQL 查询

如何将 SQL 中的 2 个表与 1 个公共列组合在一起,而其他列中没有关系?

SQL 删除行,其中一个值与 DIFFERENT 列中的值匹配

Excel - 如何比较 2 列中的单元格,然后如果 B 列匹配,则使用 B 列中匹配单元格旁边的 C 列中的值?

比较 2 个表中的值并生成具有差异的新表

在 SQL 中处理“不匹配时”(如何正确合并)