判断从表的外键是否包含所有主表的主键

我们知道数据库中有以下几个概念:

  • 主键:一般情况下,满足第一范式的表都有一个主键Primary key,用于唯一标示数据库中的一个字段
  • 外键: 外键是相对于数据库设计中的参考完整性而言,它与主键之间是彼此依赖的关系。
  • 主表: 在数据库中建立的表格即Table,其中存在主键(primary key)用于与其它表相关联,并且作为在主表中的唯一性标识
  • 从表: 以主表的主键(primary key)值为外键 (Foreign Key)的表,可以通过外键与主表进行关联查询。从表与主表通过外键进行关联查询

有如下两个表,主表是fansArr,是粉丝的信息记录。主键:fans_id,格式为 xxx-xxx-xx 表示一个32位的字符,避免重复。

const fansArr = [
    {
        fans_id: 'xxx-xxx-xx1',
        name: 'xx'
    },
    {
        fans_id: 'xxx-xxx-xx2',
        name: 'xy'
    }
];

从表是imgArr, 是所有粉丝图片的记录。外键是 fansId,

const imgArr = [
    {
        fansId: 'xxx-xxx-xx1',
        imgUrl: 'xxxx.jpg'
    },
    {
        fansId: 'xxx-xxx-xx1',
        imgUrl: 'xxxx.jpg'
    },
    {
        fansId: 'xxx-xxx-xx2',
        imgUrl: 'xxxx.jpg'
    },
    {
        fansId: 'xxx-xxx-xx1',
        imgUrl: 'xxxx.jpg'
    }
];

不难发现,粉丝和粉丝个人图片是 一对多 的关系。

问题

现在有个需求,每个粉丝至少一张图片,怎么校验?

解法一: 外键去重
弊端:性能低,因为一对多的关系,当外表记录的信息太多时,遍历次数太多。

 /**
  * 遍历 imgArr 数组,得到所有 fansId 
  */
function emptyFn1() {
    let arr = [];
    imgArr.forEach( img => {
        if(!arr.includes(img.fansId)) {
            arr.push(img.fansId)
        }
    })
    return arr.length !== fansArr.length
}

哈哈哈,方法一并不总是有效的!!!仔细看看问题出在哪里?
理想情况下外表是根据主表的主键作为外键来记录信息的,但是如果主表的主键改了,而外表的外键没有更改,方法一只是保证了主键和外键的数量一致,但内容不一定一样。不信把 fansArr[0].fans_id 改成 xxx-xxx-xx3 试试

解法二: 遍历主表,获取所有在从表中出现的fans_id

 function emptyFn2() {
    let arr = [];
    let str = JSON.stringify(imgArr);
    fansArr.forEach(fans => {
        if(str.includes(fans.fans_id)) {
            arr.push(fans.fans_id)
        }
    })
    return arr.length !== fansArr.length
}

对解法二的优化:forEach 会遍历所有,实际可能并不需要遍历全部

function emptyFn3() {
    let str = JSON.stringify(imgArr);
       if(fansArr.length > 0) {
        return !fansArr.every(fans => {
            return str.includes(fans.fans_id)
        })
    }
    throw new Error('主表是空的');
}

方法 二、三的弊端
fans_id 如果不是唯一的字符串,则存在不确定性
例如 fans_id 是普通的 1, 2, 3, 则字符串中可能存在干扰项

你可能感兴趣的:(判断从表的外键是否包含所有主表的主键)