【问题标题】:Join two tables on all possible string matches在所有可能的字符串匹配上连接两个表
【发布时间】:2015-11-11 02:49:39
【问题描述】:

我有两张表,Student 和 Reference。我想在 Reference.ReferenceCode 上加入 student.code。问题是学生可以在一个代码列中有多个代码。我想以这样一种方式加入,即当学生表中有一个学生的多个代码时会产生多行。这是我所拥有的以及我尝试过的:

Student 有两列:ID & Code

|Student ID   |Code             |
|Student1     |Code1            |
|Student2     |Code1,Code2,Code3|

ReferenceCode 有两列:ReferenceCode & Description

|ReferenceCode|Description      |
|Code1        |This is code 1   |
|Code2        |This is code 2   |
|Code3        |This is code 3   |

我尝试过使用子字符串:

select a.studentID, a.code, b.ReferenceCode, b.Description
from Student a
left join Reference b --Have also tried inner join;  No difference
on b.ReferenceCode = substring(a.Code,1,len(b.ReferenceCode))

子字符串生成下表。注意,它只匹配第一个代码:

|Student ID   |Code             |ReferenceCode    |Description    |
|Student1     |Code1            |Code1            |This is code 1 |
|Student2     |Code1,Code2,Code3|Code1            |This is code 1 |

我也试过like方法:

select a.studentID, a.code, b.ReferenceCode, b.Description
from Student a
left join Reference b --Have also tried inner join;  No difference
on b.ReferenceCode like '%' + a.Code + '%'

但是这种方法导致的表只匹配学生表中只有一个代码的记录:

|Student ID   |Code             |ReferenceCode    |Description    |
|Student1     |Code1            |Code1            |This is code 1 |
*Student 2 doesn't pull*

我想看到的是这样的:

|Student ID   |Code             |ReferenceCode    |Description    |
|Student1     |Code1            |Code1            |This is code 1 |
|Student2     |Code1,Code2,Code3|Code1            |This is code 1 |
|Student2     |Code1,Code2,Code3|Code2            |This is code 2 |
|Student2     |Code1,Code2,Code3|Code3            |This is code 3 |

【问题讨论】:

  • 如果你不介意我问,你能改变数据库的结构吗?如果可以的话,值得花时间这样做,而不是尝试以目前的方式迎合这种结构。
  • @GrandMasterFlush 的意思是您在单列中有分隔值。这违反了 1NF 并使查询比应有的更痛苦。如果您绝对无法解决此问题,那么您需要一个字符串拆分器。你可以在这里找到一篇关于这类事情的好文章。 sqlperformance.com/2012/07/t-sql-queries/split-strings
  • @GrandMasterFlush 这是我非常非常想要发生的事情。问题在于业务问题 - 这些文件是来自供应商给我们的文件,等待最终修复可能比我编写代码要慢。
  • 运气不好。我认为大多数开发人员以前都处于那个位置!

标签: sql-server join


【解决方案1】:

您提出的解决方案将存在严重的性能问题。你能改变数据库模式吗?如果是这样,以下是更好的方法。

您正在定义多对多映射。要正确映射它,您需要一个单独的“映射”表,其中仅包含学生和参考代码表中的 id。

所以你的新模式应该是这样的:

学生桌

| Student ID (int) |
| 1                |
| 2                |

学生代码表

| StudentId (int) | ReferenceCodeId (int) |
| 1               | 1                     |
| 2               | 1                     |
| 2               | 2                     |
| 2               | 3                     |

参考代码表

|ReferenceCodeId (int) | Description     | 
|1                     |This is code 1   |
|2                     |This is code 2   |
|3                     |This is code 3   |

那么您的查询将如下所示:

select s.StudentId, rc.Description 
from Student s 
left join StudentCode sc on s.StudentId = sc.StudentId
left join ReferenceCode rc on sc.ReferenceCodeId = rc.ReferenceCodeId

您的结果将如下所示:

|StudentId| Description     | 
|1        |This is code 1   |
|2        |This is code 1   |
|2        |This is code 2   |
|2        |This is code 3   |

快速搜索“sql 多对多关系”应该会为您提供重要的参考资料。

【讨论】:

  • 谢谢弗朗西斯科。这看起来像我将不得不采取的路线。我感谢额外的搜索材料。
【解决方案2】:

您可以创建一个内联用户定义函数,该函数生成一列行(每个逗号分隔值对应一行) - 然后您将能够加入该列。

这类函数通常会有代码用 XML 标记替换分隔符,然后从 XML 中进行选择,也可以是 CLR 或许多其他方法。你可以在this article找到一些东西,在那里你会发现不同的方法和性能比较结果。

【讨论】:

  • 感谢您的回复。我可能会将这一策略与另一个回复中提到的策略相结合,并重新组织通过我办公室的数据文件。欣赏额外的阅读材料。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-02-27
  • 2011-08-31
  • 1970-01-01
  • 2015-01-11
相关资源
最近更新 更多