SQL - получение данных из объединений, если другие объединения не заданы - PullRequest
0 голосов
/ 09 января 2020

Я пробовал много решений, но пока не нашел подходящего. Любая помощь приветствуется. Я использую SQL Сервер.

У меня есть несколько таких таблиц:

АВТОМОБИЛИ

+-------+-----------------+-----------------+
| 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 and CarNames. Однако я хочу, чтобы эти данные были перезаписаны таблицами Cars_Nicks и Cars_Nicks_Names, если они существуют.

В нашем приложении у каждого пользователя в основном есть «учитель». И настройки для каждого учителя также будут настройками по умолчанию для каждого из его учеников, если ученик сам не настроил ники. Таким образом, в этом случае UserId 1 является «учителем» для UserId 2. Так вот почему в таблице UserId 2 у них есть некоторые данные для UserId 1, но также и их собственные ники, в дополнение к информации о машинах по умолчанию, если определенная точка данных не существует в никах.

Я пробовал разные решения, чтобы это произошло с JOIN, UNION, GROUP BY, DISTINCT, и со всеми комбинациями, которые я мог придумать с этими. Но я продолжаю получать несколько результатов, таких как следующая таблица:

Автомобили (для 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;

Ответы [ 2 ]

1 голос
/ 09 января 2020

Используйте LEFT JOIN для объединения различных таблиц без дублирования ключей соединения. Вы должны (внешние) объединить все три таблицы Cars, Cars_Nicks и Cars_Nicks_Names только один раз, используя CarId и NickId в качестве соответствующих ключей объединения. Это, естественно, приводит к созданию нескольких записей на CarId, но (если я правильно понимаю вашу модель данных) должно выдаваться только один псевдоним на CarId, User и Language максимум. Вам нужно будет объединить псевдонимы учителя как еще одну копию таблиц Cars_Nicks и Cars_Nicks_Names, соответственно переименованных, чтобы вы могли определить, идет ли псевдоним от ученика или учителя.

Используйте COALESCE, чтобы одна вещь имела приоритет над другой. В предложении SELECT вы сделаете нечто похожее на первоначально опубликованную попытку для полей, в которых вы хотите, чтобы значение из одной из таблиц переопределило значение в поле из другой таблицы, и последний элемент в каждом списке должен быть предельное запасное значение.

Не используйте 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

0 голосов
/ 09 января 2020

Я думаю, что вы хотите inner join таблицы cars, cars_nicks и car_names, а затем ввести car_nick_names с left join. Затем вы можете реализовать логику подстановки c с помощью 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, поэтому я принудительно это к фиксированному значению. В реальном мире у вас будет таблица users, в которой хранится язык пользователя, и вы будете использовать это значение для фильтрации.

...