在开发中因为不谨慎遇到了这样一个问题,这里总结一下问题、问题出现的原因和解决方式。
假如现在有这么一个需求,
表1
表2
想要从表1中筛选出masterMerchantNo或slaveMerchantNo其中任意一个字段的值等于表2的merchantNo(也就是在表2中的merchantNo中存在这个值)的所有记录的表1的相关信息。
所以我一开始想到的是两表查询然后过滤条件,也就是两个条件OR就可以了(tb1.masterMerchantNo = tb2.merchantNo OR tb1.slaveMerchantNo = tb2.merchantNo),原先编写的sql如下:
SELECT
tb1.batchNo,
tb1.masterSettleUnitID,
tb1.masterMerchantNo,
tb1.slaveSettleUnitID,
tb1.slaveMerchantNo,
tb1.activityType,
tb1.operatorInfo,
tb1.submitTime,
tb1.bindStatus,
tb1.returnCode,
tb1.returnMsg,
tb1.unbindTime
FROM
tbl_fsm_settle_activity_mergeRecord tb1
INNER JOIN (
SELECT
merchantNo
FROM
tbl_fsm_settle_unit
WHERE
groupID = 1155
AND openPayStatus = 40
) tb2 ON tb1.masterMerchantNo = tb2.merchantNo
OR tb1.slaveMerchantNo = tb2.merchantNo
WHERE
action in ( 0 , 1 )
然后发现了问题,正常按照需求想要的结果应该是筛选后只有一条记录,就是表1这样的一条,然而如果是上面这样的sql的话,执行完后会得到两条记录,而且两条记录是一模一样的。。这显示不是我们想要的。
思考了下,发现原因,像上面这样的写法的话,sql执行首先会生成笛卡儿积,表1*表2,也就是1*2=2,总共生成2条记录,笛卡儿积应该如下:
然后在对上图所示笛卡儿积进行条件(tb1.masterMerchantNo = tb2.merchantNo OR tb1.slaveMerchantNo = tb2.merchantNo)过滤,所以这样就会得到两条重复的结果。。
所以解决这个问题的方式就是要避免笛卡儿积,所以我们避免使用多表查询sql,可以使用如下的sql:
SELECT
batchNo,
masterSettleUnitID,
masterMerchantNo,
slaveSettleUnitID,
slaveMerchantNo,
activityType,
operatorInfo,
submitTime,
bindStatus,
returnCode,
returnMsg,
unbindTime
FROM
tbl_fsm_settle_activity_mergeRecord
WHERE
action IN (0, 1)
AND (
masterMerchantNo IN (
SELECT
merchantNo
FROM
tbl_fsm_settle_unit
WHERE
groupID = 1155
AND openPayStatus = 40
)
OR slaveMerchantNo IN (
SELECT
merchantNo
FROM
tbl_fsm_settle_unit
WHERE
groupID = 1155
AND openPayStatus = 40
)
)
这样就可以避免笛卡儿积,来得到我们想要的结果。