SQL - 如果其他联接为空,则从联接获取数据
SQL - Getting data from joins if other joins are null
我已经尝试了很多解决方案,但还没有找到一个合适的解决方案。任何帮助表示赞赏。我正在使用 SQL 服务器。
我有一些像这样的table:
汽车
+-------+-----------------+-----------------+
| CarId | CarImage | CarVideo |
+-------+-----------------+-----------------+
| 1 | http://imageurl | http://videourl |
| 2 | http://imageurl | http://videourl |
| 3 | http://imageurl | http://videourl |
| 4 | http://imageurl | http://videourl |
+-------+-----------------+-----------------+
车名
+----+-------+---------+------------+
| Id | CarId | CarName | LanguageId |
+----+-------+---------+------------+
| 1 | 1 | Car 1 | 1 |
| 2 | 1 | Bil 1 | 2 |
| 3 | 2 | Car 2 | 1 |
| 4 | 2 | Bil 2 | 2 |
| 5 | 3 | Car 3 | 1 |
| 6 | 3 | Bil 3 | 2 |
| 7 | 4 | Car 4 | 1 |
| 8 | 4 | Bil 4 | 2 |
+----+-------+---------+------------+
CARS_NICKS
+--------+--------+-------+---------------------+---------------------+
| NickId | UserId | CarId | CarImage | CarVideo |
+--------+--------+-------+---------------------+---------------------+
| 1 | 1 | 1 | | |
| 2 | 1 | 2 | http://NEW-imageurl | |
| 3 | 1 | 3 | | http://NEW-videourl |
| 4 | 2 | 1 | | http://NEW-videourl |
+--------+--------+-------+---------------------+---------------------+
CARS_NICKS_NAMES
+----+--------+--------------+------------+
| Id | NickId | CarName | LanguageId |
+----+--------+--------------+------------+
| 1 | 1 | Nickname 1 | 1 |
| 2 | 1 | Nicknavn 1 | 2 |
| 3 | 4 | Nickname 1-2 | 1 |
| 4 | 4 | Nicknavn 1-2 | 2 |
| 5 | 2 | Nickname 2 | 1 |
| 6 | 2 | Nicknavn 2 | 2 |
+----+--------+--------------+------------+
我想做的是显示一个汽车列表,像这样:
汽车(对于 UserId 1)
+-------+------------+---------------------+---------------------+
| CarId | CarName | CarImage | CarVideo |
+-------+------------+---------------------+---------------------+
| 1 | Nickname 1 | http://imageurl | http://videourl |
| 2 | Nickname 2 | http://NEW-imageurl | http://videourl |
| 3 | Car 3 | http://imageurl | http://NEW-videourl |
| 4 | Car 4 | http://imageurl | http://videourl |
+-------+------------+---------------------+---------------------+
汽车(对于 UserId 2)
+-------+--------------+---------------------+---------------------+
| CarId | CarName | CarImage | CarVideo |
+-------+--------------+---------------------+---------------------+
| 1 | Nickname 1-2 | http://imageurl | http://NEW-videourl |
| 2 | Nickname 2 | http://NEW-imageurl | http://videourl |
| 3 | Car 3 | http://imageurl | http://NEW-videourl |
| 4 | Car 4 | http://imageurl | http://videourl |
+-------+--------------+---------------------+---------------------+
这是在做什么,基本上是从 Cars 和 CarNames table 中获取每辆汽车的所有默认信息。但是,我希望此数据被 Cars_Nicks 和 Cars_Nicks_Names table 覆盖(如果存在)。
在我们的应用中,每个User基本上都有一个"teacher"。每个老师的设置也将是每个学生的默认设置,除非学生自己也设置了刻痕。所以在这种情况下,UserId 1 是 UserId 2 的 "teacher"。这就是为什么在 UserId 2 的 table 中,除了默认的 Cars 之外,他们还有一些 UserId 1 的数据,还有他们自己的昵称如果刻痕中不存在某个数据点的信息。
我尝试了不同的解决方案来实现 JOIN
、UNION
、GROUP BY
、DISTINCT
以及我能想到的所有组合。但我一直以多个结果结束,例如以下 table:
汽车(对于 UserId 2)(我的尝试)
+-------+--------------+---------------------+---------------------+
| CarId | CarName | CarImage | CarVideo |
+-------+--------------+---------------------+---------------------+
| 1 | Nickname 1 | http://imageurl | http://videourl |
| 1 | Nickname 1-2 | http://imageurl | http://NEW-videourl |
| 2 | Nickname 2 | http://NEW-imageurl | http://videourl |
| 2 | Car 2 | http://imageurl | http://videourl |
| 3 | Car 3 | http://imageurl | http://NEW-videourl |
| 3 | Car 3 | http://imageurl | http://videourl |
| 4 | Car 4 | http://imageurl | http://videourl |
+-------+--------------+---------------------+---------------------+
有人知道我如何得到这个吗?
这是我的众多尝试之一:
SELECT
CarId,
ISNULL(CarNicks.CarName, CarNames.CarNames) CarNames,
ISNULL(CarNicks.CarImage, Cars.CarImage) CarImage,
ISNULL(CarNicks.CarVideo, Cars.CarVideo) CarVideo
FROM
Cars
LEFT JOIN
(SELECT CarId, CarName, CarImage, CarVideo
FROM Cars_Nicks Nicks
JOIN Cars_Nicks_Names NickNames ON NickNames.NickId = Nicks.NickId
AND NickNames.LanguageId = 1 AND UserId = 1
UNION
SELECT CarId, CarName, CarImage, CarVideo
FROM Cars_Nicks Nicks
JOIN Cars_Nicks_Names NickNames ON NickNames.NickId = Nicks.NickId
AND NickNames.LanguageId = 1 AND UserId = 2) CarNicks ON CarNicks.CarId = Cars.CarId
JOIN
CarNames ON CarNames.CarId = Cars.CarId;
使用 LEFT JOIN
将各种 table 组合在一起,而无需复制连接键。您应该(外部)加入所有三个 tables Cars
、Cars_Nicks
和 Cars_Nicks_Names
一次,使用 CarId
和 NickId
作为各自的加入键。这自然会为每个 CarId
生成多个记录,但是(如果我正确理解您的数据模型)应该最多为每个 CarId
、User
和 Language
生成一个昵称。您需要将老师的昵称作为 Cars_Nicks
和 Cars_Nicks_Names
table 的 的另一个副本 添加,适当重命名以便您可以识别昵称来自学生或老师。
使用COALESCE
使一件事优先于另一件事。在 SELECT
子句中,您将对您希望 table 之一的值覆盖另一个 table 的字段中的值的字段执行类似于您最初发布的尝试的操作, 每个列表中的最后一项应该是最终的回退值。
在这种情况下不要使用 UNION
。
以下只是名称的未经测试的示例。扩展要连接的内容以在输出中包含您想要的其他字段相当容易。
select Cars.CarId, Cars.LanguageId, coalesce( StudentNN.CarName, TeacherNN.CarName, Cars.CarName ) as CarName
from
Car_Names left join (
select NickId from Cars_Nicks where UserId = :student
) StudentN using (CarId)
left join (
select NickId from Cars_Nicks where UserId = :teacher
) TeacherN using (CarId)
left join (
select CarName from Cars_Nicks_Names
) StudentNN on StudentN.NickId = StudentNN.NickId and Car_Names.LanguageId = StudentNN.LanguageId
left join (
select CarName from Cars_Nicks_Names
) TeacherNN on TeacherN.NickId = TeacherNN.NickId and Car_Names.LanguageId = TeacherNN.LanguageId
我认为你想要 inner join
tables cars
, cars_nicks
和 car_names
, 然后带入 car_nick_names
一个left join
。然后你可以用 coalesce()
:
实现替换逻辑
select
ni.userid,
ni.carid,
coalesce(nn.carname, na.carname) carname
coalesce(ni.carimage, ca.carimage) carimage,
coalesce(ni.carvideo, ca.carvideo) carvideo
from cars ca
inner join cars_nicks ni on ni.carid = ca.carid
inner join car_names na on na.carid = ca.carid and na.languageid = 1
left join cars_nicks_names nn on nn.nickid = ni.nickid and nn.language_id = 1
您没有解释如何管理 languageid
列,该列存在于 *_names
table 中,因此我将其强制为固定值。在现实世界中,您会有一个 users
table 存储用户语言,并使用该值进行过滤。
我已经尝试了很多解决方案,但还没有找到一个合适的解决方案。任何帮助表示赞赏。我正在使用 SQL 服务器。
我有一些像这样的table:
汽车
+-------+-----------------+-----------------+
| CarId | CarImage | CarVideo |
+-------+-----------------+-----------------+
| 1 | http://imageurl | http://videourl |
| 2 | http://imageurl | http://videourl |
| 3 | http://imageurl | http://videourl |
| 4 | http://imageurl | http://videourl |
+-------+-----------------+-----------------+
车名
+----+-------+---------+------------+
| Id | CarId | CarName | LanguageId |
+----+-------+---------+------------+
| 1 | 1 | Car 1 | 1 |
| 2 | 1 | Bil 1 | 2 |
| 3 | 2 | Car 2 | 1 |
| 4 | 2 | Bil 2 | 2 |
| 5 | 3 | Car 3 | 1 |
| 6 | 3 | Bil 3 | 2 |
| 7 | 4 | Car 4 | 1 |
| 8 | 4 | Bil 4 | 2 |
+----+-------+---------+------------+
CARS_NICKS
+--------+--------+-------+---------------------+---------------------+
| NickId | UserId | CarId | CarImage | CarVideo |
+--------+--------+-------+---------------------+---------------------+
| 1 | 1 | 1 | | |
| 2 | 1 | 2 | http://NEW-imageurl | |
| 3 | 1 | 3 | | http://NEW-videourl |
| 4 | 2 | 1 | | http://NEW-videourl |
+--------+--------+-------+---------------------+---------------------+
CARS_NICKS_NAMES
+----+--------+--------------+------------+
| Id | NickId | CarName | LanguageId |
+----+--------+--------------+------------+
| 1 | 1 | Nickname 1 | 1 |
| 2 | 1 | Nicknavn 1 | 2 |
| 3 | 4 | Nickname 1-2 | 1 |
| 4 | 4 | Nicknavn 1-2 | 2 |
| 5 | 2 | Nickname 2 | 1 |
| 6 | 2 | Nicknavn 2 | 2 |
+----+--------+--------------+------------+
我想做的是显示一个汽车列表,像这样:
汽车(对于 UserId 1)
+-------+------------+---------------------+---------------------+
| CarId | CarName | CarImage | CarVideo |
+-------+------------+---------------------+---------------------+
| 1 | Nickname 1 | http://imageurl | http://videourl |
| 2 | Nickname 2 | http://NEW-imageurl | http://videourl |
| 3 | Car 3 | http://imageurl | http://NEW-videourl |
| 4 | Car 4 | http://imageurl | http://videourl |
+-------+------------+---------------------+---------------------+
汽车(对于 UserId 2)
+-------+--------------+---------------------+---------------------+
| CarId | CarName | CarImage | CarVideo |
+-------+--------------+---------------------+---------------------+
| 1 | Nickname 1-2 | http://imageurl | http://NEW-videourl |
| 2 | Nickname 2 | http://NEW-imageurl | http://videourl |
| 3 | Car 3 | http://imageurl | http://NEW-videourl |
| 4 | Car 4 | http://imageurl | http://videourl |
+-------+--------------+---------------------+---------------------+
这是在做什么,基本上是从 Cars 和 CarNames table 中获取每辆汽车的所有默认信息。但是,我希望此数据被 Cars_Nicks 和 Cars_Nicks_Names table 覆盖(如果存在)。
在我们的应用中,每个User基本上都有一个"teacher"。每个老师的设置也将是每个学生的默认设置,除非学生自己也设置了刻痕。所以在这种情况下,UserId 1 是 UserId 2 的 "teacher"。这就是为什么在 UserId 2 的 table 中,除了默认的 Cars 之外,他们还有一些 UserId 1 的数据,还有他们自己的昵称如果刻痕中不存在某个数据点的信息。
我尝试了不同的解决方案来实现 JOIN
、UNION
、GROUP BY
、DISTINCT
以及我能想到的所有组合。但我一直以多个结果结束,例如以下 table:
汽车(对于 UserId 2)(我的尝试)
+-------+--------------+---------------------+---------------------+
| CarId | CarName | CarImage | CarVideo |
+-------+--------------+---------------------+---------------------+
| 1 | Nickname 1 | http://imageurl | http://videourl |
| 1 | Nickname 1-2 | http://imageurl | http://NEW-videourl |
| 2 | Nickname 2 | http://NEW-imageurl | http://videourl |
| 2 | Car 2 | http://imageurl | http://videourl |
| 3 | Car 3 | http://imageurl | http://NEW-videourl |
| 3 | Car 3 | http://imageurl | http://videourl |
| 4 | Car 4 | http://imageurl | http://videourl |
+-------+--------------+---------------------+---------------------+
有人知道我如何得到这个吗?
这是我的众多尝试之一:
SELECT
CarId,
ISNULL(CarNicks.CarName, CarNames.CarNames) CarNames,
ISNULL(CarNicks.CarImage, Cars.CarImage) CarImage,
ISNULL(CarNicks.CarVideo, Cars.CarVideo) CarVideo
FROM
Cars
LEFT JOIN
(SELECT CarId, CarName, CarImage, CarVideo
FROM Cars_Nicks Nicks
JOIN Cars_Nicks_Names NickNames ON NickNames.NickId = Nicks.NickId
AND NickNames.LanguageId = 1 AND UserId = 1
UNION
SELECT CarId, CarName, CarImage, CarVideo
FROM Cars_Nicks Nicks
JOIN Cars_Nicks_Names NickNames ON NickNames.NickId = Nicks.NickId
AND NickNames.LanguageId = 1 AND UserId = 2) CarNicks ON CarNicks.CarId = Cars.CarId
JOIN
CarNames ON CarNames.CarId = Cars.CarId;
使用 LEFT JOIN
将各种 table 组合在一起,而无需复制连接键。您应该(外部)加入所有三个 tables Cars
、Cars_Nicks
和 Cars_Nicks_Names
一次,使用 CarId
和 NickId
作为各自的加入键。这自然会为每个 CarId
生成多个记录,但是(如果我正确理解您的数据模型)应该最多为每个 CarId
、User
和 Language
生成一个昵称。您需要将老师的昵称作为 Cars_Nicks
和 Cars_Nicks_Names
table 的 的另一个副本 添加,适当重命名以便您可以识别昵称来自学生或老师。
使用COALESCE
使一件事优先于另一件事。在 SELECT
子句中,您将对您希望 table 之一的值覆盖另一个 table 的字段中的值的字段执行类似于您最初发布的尝试的操作, 每个列表中的最后一项应该是最终的回退值。
在这种情况下不要使用 UNION
。
以下只是名称的未经测试的示例。扩展要连接的内容以在输出中包含您想要的其他字段相当容易。
select Cars.CarId, Cars.LanguageId, coalesce( StudentNN.CarName, TeacherNN.CarName, Cars.CarName ) as CarName
from
Car_Names left join (
select NickId from Cars_Nicks where UserId = :student
) StudentN using (CarId)
left join (
select NickId from Cars_Nicks where UserId = :teacher
) TeacherN using (CarId)
left join (
select CarName from Cars_Nicks_Names
) StudentNN on StudentN.NickId = StudentNN.NickId and Car_Names.LanguageId = StudentNN.LanguageId
left join (
select CarName from Cars_Nicks_Names
) TeacherNN on TeacherN.NickId = TeacherNN.NickId and Car_Names.LanguageId = TeacherNN.LanguageId
我认为你想要 inner join
tables cars
, cars_nicks
和 car_names
, 然后带入 car_nick_names
一个left join
。然后你可以用 coalesce()
:
select
ni.userid,
ni.carid,
coalesce(nn.carname, na.carname) carname
coalesce(ni.carimage, ca.carimage) carimage,
coalesce(ni.carvideo, ca.carvideo) carvideo
from cars ca
inner join cars_nicks ni on ni.carid = ca.carid
inner join car_names na on na.carid = ca.carid and na.languageid = 1
left join cars_nicks_names nn on nn.nickid = ni.nickid and nn.language_id = 1
您没有解释如何管理 languageid
列,该列存在于 *_names
table 中,因此我将其强制为固定值。在现实世界中,您会有一个 users
table 存储用户语言,并使用该值进行过滤。