2015-10-02 3 views
2

Мне нужна помощь в оптимальном структурировании SQL-запроса. У меня есть модель, как это:
segment of database modelПрисоединение и фильтрация отношений «один ко многим»

Я пытаюсь своего рода объединение между таблицами NON_NATURAL_PERSON и NNP_NAME. Поскольку у меня есть много имен в таблице NNP_NAME для одного человека, я не могу делать один на один SELECT * from NON_NATURAL_PERSON inner join NNP_NAME и т. Д. Таким образом, я получаю дополнительные строки для каждого имени, которое есть у одного человека.

данных в таблицах:
PERSON dataNON_NATURAL_PERSON dataNNP_NAME data
Как продлить этот запрос, чтобы получить строки, отмеченные красным на картинке показано ниже? Мои критерии запроса wannabe: Всегда присоединяйте имя typeA только в том случае, если оно существует. Если нет, присоедините имя типаB. Если не существует имени соединения typeC.

SELECT nnp.ID, name.NAME, name.TYPE 
FROM NON_NATURAL_PERSON nnp 
INNER JOIN NNP_NAME name ON (name.NON_NATURAL_PERSON = nnp.ID) 

query result

+0

любая конкретная причина, по которой вы отметили как 'mysql', так и' h2'? – sstan

+0

@sstan № Я нацелен на универсальный SQL. Мои тестовые платформы - это MySQL и H2 – shx

ответ

1

Если тип пишется именно так, как это написано (TypeA, TypeB, typeC), то вы можете использовать функцию MIN():

SELECT NON_NATURAL_PERSON, MIN(type) AS min_type 
FROM NNP_NAME 
GROUP BY NON_NATURAL_PERSON 

, если вы хотите, имя пользователя вы можете использовать этот запрос:

SELECT 
    n1.NON_NATURAL_PERSON AS ID, 
    n1.Name, 
    n1.Type 
FROM 
    NNP_NAME n1 LEFT JOIN NNP_NAME n2 
    ON n1.NON_NATURAL_PERSON = n2.NON_NATURAL_PERSON 
    AND n1.Type > n2.type 
WHERE 
    n2.type IS NULL 

См. это fiddle. Если типы не буквально сортируют, изменить эту строку:

 AND n1.Type > n2.type 

с этим:

 AND FIELD(n1.Type, 'TypeA', 'TypeB', 'TypeC') > 
     FIELD(n2.type, 'TypeA', 'TypeB', 'TypeC') 

MySQL FIELD (ул str1, str2, ...) функция возвращает индекс (положение) ул в str1, str2, ... list и 0, если str не найден. Вы хотите получить «первую» запись, упорядоченную по типу, для каждого NON_NATURAL_PERSON. Есть несколько способов, чтобы получить эту информацию, я выбрал автообъединение:

ON n1.NON_NATURAL_PERSON = n2.NON_NATURAL_PERSON 
    AND n1.Type > n2.type -- or filed function 

с условием WHERE:

WHERE n2.type IS NULL 

это вернет все строки, где инфу не удалось - объединение вон 't преуспеть, когда нет n2.type, который меньше n1.type - он вернет первую запись.

Редактировать

Если вы хотите платформонезависимый решение, избегая при этом создания новых таблиц, вы можете использовать случай, когда просто изменить

AND n1.Type > n2.Type 

с

AND 
    CASE 
    WHEN n1.Type='TypeA' THEN 1 
    WHEN n1.Type='TypeB' THEN 2 
    WHEN n1.Type='TypeC' THEN 3 
    END 
    > 
    CASE 
    WHEN n2.Type='TypeA' THEN 1 
    WHEN n2.Type='TypeB' THEN 2 
    WHEN n2.Type='TypeC' THEN 3 
    END 
+0

Типы не сортируются в прямом порядке. Как бы то ни было, для тестовых целей – shx

+1

@shx см. Мой обновленный ответ – fthiella

+0

Спасибо человеку. Но есть ли другой способ, кроме использования функции FIELD(), определенной mysql? Можете ли вы немного объяснить, почему вы используете объединение двух одинаковых таблиц nnp_name? – shx

1

Там это недостающая информация. Вы говорите:

Always join name of typeA only if exists. If not, join name of typeB. If neither exists join name of typeC. 

Но вы не показываете почему вы предпочитаете TypeA над TypeB.Эта информация не включена в ваши данные. В ответе @fthiella предполагается либо лексикографический, либо произвольный порядок задается с использованием FIELD. Это также является причиной того, что необходимы два соединения с таблицей nnp_name.

Вы можете решить эту проблему, добавив таблицу name_type (id, name, order) и изменив столбец типа, чтобы он содержал идентификатор. Это позволит вам добавить недостающую информацию в чистом виде.

С дополнительным соединением с этой новой таблицей вы сможете получить предпочтительное имя nnp для каждой строки.

+0

Вы правы. Дополнительная таблица будет самым чистым способом, но у меня нет такой возможности. Мне нужно будет сделать некоторый случай/когда/тогда логика, потому что typeA может быть FOO, typeB может быть BAR и т. Д. – shx

Смежные вопросы