筛选可能为空的SQL行

问题描述

我正在尝试在Kotlin Exposed中编写一个查询,该查询将多个表连接在一起。一些表可以具有空值,在这种情况下,select语句应该忽略这些值。

一个示例中:我有一个UserTable一个GeoLocationTable一个PhotoTable用户将始终具有一个引用的GeoLocation表,但是该表可能包含照片,也可能没有照片。 UserTablePhotoTable一无所知,但是PhotoTable一个userId作为FK。

我想实现这一点,当我查询用户时-我总是在结果集中收到一个用户。仅当存在带有userId作为外键的照片时,这些照片才应位于结果集中,否则结果集应仅包含用户

我的问题是,如果用户的照片不在数据库中,那么我的查询甚至不会返回用户!我在做什么错了?

这是查询

    private fun fetchUserWithPhotos(userId: String) = tx {
        val query = UserProfileTable
            .join(
                joinType = JoinType.LEFT,otherTable = GeoLocationTable,otherColumn = GeoLocationTable.id,onColumn = UserProfileTable.geoLocationId
            )
            .join(
                joinType = JoinType.LEFT,otherTable = PhotoTable,otherColumn = PhotoTable.userId,onColumn = UserProfileTable.id
            )

        val x = query
            .select {
                (UserProfileTable.id eq userId) and
                    (UserProfileTable.deletedAt.isNull()) and
                    (UserProfileTable.enabled eq true) and
                    (PhotoTable.userPhotoType eq UserPhotoType.PROFILE.toString()) and
                    (PhotoTable.position eq 1)
            }
        // x is empty set here,even though the user EXISTS!
    }

如何总是获取用户,以及只有存在的照片?

解决方法

我想我很直接,我可以从您的代码中解析出的查询可以解决这个问题:

select * from user_profile
left join geo_location on user_profile.geo_location_id = geo_location.id
left join photo on user_profile.id = photo.user_id
where user_profile.id = ? 
and user_profile.deleted_at is null 
and user_profile.enabled  is true
and photo.user_photo_type = 'PROFILE'
and photo.position = 1;

您描述的问题是:'如果该用户的照片不在数据库中,那么我的查询甚至不会返回该用户!我在做什么错?'

问题:您使用的是基于照片表中数据的谓词,您已经声明用户不一定总是有照片条目。如果没有照片,则谓词为假,即使您知道用户存在,也不会选择该行:

and photo.user_photo_type = 'PROFILE'
and photo.position = 1;

建议的解决方案:我认为您可以尝试加入所需的照片并仅在用户表上保留谓词。将查询更新为:

select * from user_profile
left join geo_location on user_profile.geo_location_id = geo_location.id
left join photo on user_profile.id = photo.user_id and photo.position = 1 and photo.user_photo_type = 'PROFILE'
where user_profile.id = ? 
and user_profile.deleted_at is null 
and user_profile.enabled  is true;