一个复杂的sql问题

一个复杂的sql问题,sql,Sql,我有两张桌子: CREATE TABLE [dbo].[Customer] ( [CustomerName] VARCHAR(20) NOT NULL, [CustomerLink] VARCHAR(40) NULL ) CREATE TABLE [dbo].[CustomerIdentification] ( [CustomerName] VARCHAR(20) NOT NULL, [ID] VARCHAR(50) NOT

我有两张桌子:

CREATE TABLE [dbo].[Customer]
(
    [CustomerName]  VARCHAR(20)  NOT NULL,
    [CustomerLink]  VARCHAR(40)  NULL
)

CREATE TABLE [dbo].[CustomerIdentification]
(
    [CustomerName]  VARCHAR(20)  NOT NULL,
    [ID]            VARCHAR(50)  NOT NULL,
    [IDType]        VARCHAR(16)  NOT NULL
)
我还添加了一些测试数据

INSERT  [dbo].[Customer]
        ([CustomerName])
VALUES  ('Fred'),
        ('Bob'),
        ('Vince'),
        ('Tom'),
        ('Alice')

INSERT  [dbo].[CustomerIdentification]
VALUES  
        ('Fred',   'A',  'Passport'),
        ('Fred',   'A',  'SIN'),
        ('Fred',   'A',  'Drivers Licence'),
        ('Bob',    'A',  'Passport'),
        ('Bob',    'B',  'Drivers Licence'),
        ('Bob',    'C',  'Credit Card'),
        ('Vince',  'A',  'Passport'),
        ('Vince',  'B',  'SIN'),
        ('Vince',  'C',  'Credit Card'),
        ('Tom',    'A',  'Passport'),
        ('Tom',    'B',  'SIN'),
        ('Tom',    'A',  'Drivers Licence'),
        ('Alice',  'B',  'Drivers Licence')
基本上,一个客户(来自客户表)可以有许多标识。例如,Fred有passport、sin和驾驶执照,三个值都是A(值也可能不同)

这是我想要的输出:

测试1:带有A值的护照

从表中:第一个常见标识是Passport,值为A:4个客户拥有此ID。Fred、Bob、Vince和Tom可能都是同一个客户,如果是这样,我们希望在customer表的CustomerLink字段中使用唯一的ID(guid)链接所有4个客户

但是,如果客户之间有1个ID匹配,那么如果其中任何一个具有其他公共ID类型,那么其他客户也应该匹配。例如,Fred的SIN值为a,Vince和Tom也有SIN值,但值为B。因此,该组不是同一客户。没有链接完成

测试2:值为B的SIN

下一个常见的标识是Vince和Tom的值为B的SIN。文斯和汤姆确实是同一个客户,因为他们也有相同价值的护照(A)。两者的第三个标识具有不同的ID类型、信用卡和驾驶执照。因此,它们可以链接。所以我们将文斯和汤姆链接为客户表中的同一客户

测试3:值为A的驾驶执照

这对弗雷德和汤姆来说是存在的。两人都有护照,护照也有价值。两者都有共同的罪,然而,罪的价值是不同的。A给弗雷德,B给汤姆。因此,他们不是同一个客户。没有链接完成

测试4:值为B的驾驶执照

对鲍勃和爱丽丝来说是存在的。他们确实是同一个客户,因为Bob和Alice都有值为B的驾驶执照。Bob还有另外两个Alice没有的ID,这很好,因为这些ID是Bob独有的。所以我们将Bob和Alice链接为customer表中的同一个customer

测试5:值为C的信用卡

这对鲍勃和文斯来说是存在的

但是鲍勃已经和爱丽丝联系在一起了,所以我们必须把爱丽丝带到照片里。 文斯已经和汤姆有联系了,所以我们必须把汤姆带到照片里

现在,Bob拥有值为B的Drivers License,Tom也拥有值为A的Drivers License。不同的值但相同的ID(Drivers License)导致此组无法链接。因此,没有链接,以前的链接仍然存在


最后,我们只剩下文斯和汤姆,还有鲍勃和爱丽丝作为客户表中的相同客户进行链接。所以客户表可能看起来像

CustomerName    Customer Link
------------    -------------
Fred            NULL
Bob             YYYYYY
Vince           XXXXXX
Tom             XXXXXX 
Alice           YYYYYY

您需要的关系运算符是,通常称为


因为你认为有三行的鲍伯和只有一行的爱丽丝是一样的,你应该看看。与该链接中的示例不同,您需要从红利表

CustomerIdentification
派生除数表。空除数在您的情况下不是问题。

我有个问题。如果我们有这些行,会发生什么:

INSERT  [dbo].[CustomerIdentification]
VALUES  
        ('Morheus',   'A',  'Passport'),
        ('Morheus',   'B',  'SIN'),

        ('Neo',       'B',  'SIN'),
        ('Neo',       'C',  'Drivers Licence'),

        ('Trinity',   'C',  'Drivers Licence'),
        ('Trinity',   'A',  'Passport') ;
是否应将他们全部3人归入同一组(视为同一客户)

编辑:OP回复说,这三家公司应被视为同一客户


在这种情况下会发生什么:

INSERT  [dbo].[CustomerIdentification]
VALUES  
        ('Morheus',   'A',  'Passport'),
        ('Morheus',   'B',  'SIN'),

        ('Neo',       'B',  'SIN'),
        ('Neo',       'C',  'Drivers Licence'),

        ('Trinity',   'C',  'Drivers Licence'),
        ('Trinity',   'D',  'Passport') ;       --- the only change from previous
现在,
Morheus
应该是与
Neo
相同的客户(相同的
SIN
,没有其他冲突)

Neo
应该是与
Trinity
相同的客户(相同的
驾照
,没有其他冲突)

但是
Trinity
Morheus
有不同的护照

EDIT:OP回答说,如果我们首先检查
Morheus
Neo
,那么它们应该被视为一个整体。然后,
Trinity
应该被拒绝,因为她的护照与
Morheus
冲突

我假设如果我们先检查Neo和Trinity,那么他们应该被视为一体,然后应该拒绝Morheus,因为他的护照与Trinity有冲突


我的结论是,这个问题在关系术语中定义不清。仅使用关系逻辑是无法解决的。它可能可以通过变量或分析扩展来解决,例如
行数()

我又看了一眼,但没走多远

首先,将EAV的设计修改为“更相关的”(包括空值,但不要紧!):

接下来,自行连接以查找至少具有一个匹配属性的成对客户:

SELECT c1.CustomerName, c2.CustomerName
  FROM dbo.Customers c1
       JOIN dbo.Customers c2
          ON c1.CustomerName < c2.CustomerName
             AND (
                  c1.Credit_Card = c2.Credit_Card
                  OR c1.Drivers_Licence = c2.Drivers_Licence
                  OR c1.Passport = c2.Passport
                  OR c1.SIN = c2.SIN
                 );

接下来,我们需要根据逻辑消除Bob和Vince对,“Bob已经与Alice关联,因此我们必须将Alice引入图片中。Vince已经与Tom关联,因此我们必须将Tom引入图片中。”这意味着递归或分层(在森林中寻找树?),此时我退出。

伪装成问题的家庭作业?@a'b'c'd'e'f'g'h,这里不太伪装=)有趣的问题,但它是家庭作业吗?如果是这样的话,为了公平起见,在上面贴上家庭作业标签。你自己也尝试过解决这个问题吗?有没有一个特别的领域你正在挣扎?这不是家庭作业。我以前用另一种语言问过这个问题,但人们听不懂。()所以我把它简化了很多,现在看起来像是家庭作业。我真的试过了,但我无法理解其中的逻辑。另一个线程上的Tom做了一个很好的尝试,但是他的逻辑仍然没有产生预期的结果。如果您能回复一个示例代码,我将不胜感激。我有点累了。有一天我向你道歉。我会读那些文章。只是我已经做了一个星期了,我有点脑力枯竭。如果有人能提出一个有效的解决方案。。。。我想我是不讲道理了。好吧,谢谢你试着帮我解决问题。在您的第一个测试用例中,Morphese和Trinity具有相同的passport值A,其他两个IDType SIN和DRIV LIC不同,所以是的,它们是相同的
SELECT c1.CustomerName, c2.CustomerName
  FROM dbo.Customers c1
       JOIN dbo.Customers c2
          ON c1.CustomerName < c2.CustomerName
             AND (
                  c1.Credit_Card = c2.Credit_Card
                  OR c1.Drivers_Licence = c2.Drivers_Licence
                  OR c1.Passport = c2.Passport
                  OR c1.SIN = c2.SIN
                 );
SELECT c1.CustomerName, c2.CustomerName
  FROM dbo.Customers c1
       JOIN dbo.Customers c2
          ON c1.CustomerName < c2.CustomerName
             AND (
                  c1.Credit_Card = c2.Credit_Card
                  OR c1.Drivers_Licence = c2.Drivers_Licence
                  OR c1.Passport = c2.Passport
                  OR c1.SIN = c2.SIN
                 )
INTERSECT
SELECT c1.CustomerName, c2.CustomerName
  FROM dbo.Customers c1
       JOIN dbo.Customers c2
          ON c1.CustomerName < c2.CustomerName
             AND COALESCE(c1.Credit_Card, c2.Credit_Card, 'x') 
                    = COALESCE(c2.Credit_Card, c1.Credit_Card, 'x') 
             AND COALESCE(c1.Drivers_Licence, c2.Drivers_Licence, 'x')
                    = COALESCE(c2.Drivers_Licence, c1.Drivers_Licence, 'x')
             AND COALESCE(c1.Passport, c2.Passport, 'x')
                    = COALESCE(c2.Passport, c1.Passport, 'x')
             AND COALESCE(c1.SIN, c2.SIN, 'x')
                    = COALESCE(c2.SIN, c1.SIN, 'x');
CustomerName         CustomerName
-------------------- --------------------
Alice                Bob
Bob                  Vince
Tom                  Vince