SQL:当语法不相同时,如何从一个表中查询不在另一个表中的项目?

标签 sql ms-access

我有一个问题,因为我真的不擅长 SQL。我了解基本功能,但当
它变得有点复杂,我完全迷路了。

这是我所拥有的:
表格:tA、tB
列:tA:refA tB:refB
基本上 refA 和 refB 代表相同的东西(一些像 xxx-xxx-xxx 形式的 id),但是 refB 可以附加信息(如 xxx-xxx-xxx_Zxxx 或 xxx-xxx-xxx Zxxx)

这是我知道的方法:
查询在一个表中但不在另一个表中的项目(当它们完全相同时)

select refA
from tA
where not exists (select *
from tB
where tB.refB = tA.refA
)

我想做什么:
我想要一个查询来列出 refA 中不在 refB 中的项目。 但是,问题是,如果我像刚才展示的那样运行一个 NOT EXISTS 的“简单”查询,它将返回所有内容, 因为附加。所以我考虑使用这样的语法:

SELECT refA
FROM tA
WHERE NOT EXISTS (SELECT * 
FROM tB
WHERE tB.refB LIKE CONCAT(tA.refA,'%'))

但是……当然,这行不通。

谁能告诉我应该怎么做,并解释一下它是如何工作的,以便我学习?
提前致谢!

编辑:附加信息
我不能使用 left() 或类似的东西,因为 ref 格式相似但并不总是相同(字符数不同)。
在追加之前检测 id 结尾的唯一方法是有空格或下划线。

编辑 2:导致问题的数据样本(星期一,1 月 10 日)

这里是表格中的一些实际数据,这就是人们在这里给出的大多数答案 错过一些结果:/

在 tA 中:
B20-60-04-6A-1
B20-60-04-6A-11
B20-60-04-6A-12
B20-60-04-6A-13

以 tB 为单位:
B20-60-04-6A-11_XX
B20-60-04-6A-12_XX
B20-60-04-6A-13_XX

mid()、left() 等的问题在于,如果我们检查“B20-60-04-6A-1”(14 个字符) 针对前 14 个字符,它将返回 3 个正数,而实际上它不在 tB 中......

那么,我们该如何进行呢?

tA中数据模式的例子是这样的:
(X, XYZ: 字符。x: 字母数字)
Xxx-xx-xx-x
Xxx-xx-xx-xx
Xxx-xx-xx-xx-xx
Xxx-xx-xx-xx-xx-x
等等

tB​​ 中的数据模式示例:
Xxx-xx-xx-xx-xx-XYZ-xx Z xxx_XX
Xxx-xx-xx-xx-xx-XYZZxxx_XX
Xxx-xx-xx-xx-xx Z xxx_XX

XYZ 总是相同的 3 个字符。当我们没有 XYZ 时,总是有空格或下划线。

所以我们比较的数据串应该按照这样裁剪:
- 从开始到 -XYZ 字符串
- 或者,如果字符串中没有 -XYZ,则从开始到第一个“”或“_”

我会在 VBA 中快速编写,但在 SQL 中......好吧,我会试一试,但我真的很糟糕 :D

最佳答案

因此,首先,您需要一个函数来将 refB 更改为不包含附加信息,以便与 refA 进行正确比较。将有几种方法,但像这样的方法应该有效:

Left(tb.RefB, InStr(Replace(tb.RefB+"_", " ", "_"), "_") -1)

这会将“123-456 123 EXTRA STUFF”或“123-456_123_EXTRA_STUFF”之类的任何 refB 转换为“123-456”。该结果应该可以直接与 refA 进行比较。

编辑:对上述表达式的简短解释。我正在做的是:

  1. 在 refB 的末尾添加一个下划线,以便始终至少有一个下划线(这适用于 refB 与 refA 相同的情况,例如“123”变为“123_”)
  2. 用下划线替换 refB 中的所有空格(Replace 函数)。现在我们知道分隔符始终是下划线,并且我们从第 1 步中也知道至少会有一个下划线。
  3. 找到第一个下划线的位置(InStr 函数)。这是 refB 在 refA 和其他内容之间拆分的位置。
  4. 抓取字符串开头和第一个下划线之间的所有字符,即分隔符之前的部分。

所以,这给了你这样的东西:

select refA
from tA
where not exists (select *
from tB
where Left(tb.RefB, InStr(Replace(tb.RefB+"_", " ", "_"), "_") -1) = tA.refA
)

由于这种情况,我会使用这种方法而不是与通配符进行比较,或修剪 refB 以匹配 refA 的长度:

refA
====
123
123-456
123-456-789

refB
====
123-456-789_This_is_a_test

在这种情况下,修剪或通配符匹配 refA 与 refB 将导致所有 refA 成功,因为“123*”、“123-456*”和“123-456-789*”所有 匹配“123-456-789_This_is_a_test”。

关于SQL:当语法不相同时,如何从一个表中查询不在另一个表中的项目?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4625770/

相关文章:

vb.net - 如何将多个DataTable合并到一个DataTable中?

php - 从外键数量可变的 MySQL 数据库中获取行。

php - 如何从表中获取所有数据(包括表 ID)

php - 不允许学说 2.0 Orx

sql - 规范化为 Microsoft Access 中的第一种形式 - 是否有半自动方法?

ms-access - 从 OLE 对象链接 MS Access 2007 获取路径

ms-access - 烦人的 vba 命名行为

sql - Oracle TOP N个有序行

php函数导致sql查询失败

c# - Access 查询表达式中缺少运算符