Справка по SQL-запросу - как правильно присоединиться? - PullRequest
1 голос
/ 29 июня 2010

Скажем, если у меня есть таблица "PersonData", в которой 4 из ее столбцов:

FromPersonId, FromEmployeeId, ToPersonId, ToEmployeeId

Любая из записей содержит только одну From ** и только один To **, а два других столбца равны нулю.Кроме того, FromPersonId и ToPersonId относятся к таблице "Person", а FromEmployeeId и ToEmployeeId относятся к таблице "Employee".

Мой вопрос таков: как СОБСТВЕННО объединить PersonData с таблицей Person и Employee?

Обратите внимание, что я попробовал несколько разных подходов, но когда я делаю подсчет PersonData, я получаю разные результаты при объединении (то есть он показывает больше, чем в PersonData) ...

Как мне сделать объединение?я должен сделать один для каждого FromPersonId и ToPersonId to Person и аналогичный для Сотрудника?(сомневаюсь, что это так) ...

Спасибо,

Voodoo

Ответы [ 3 ]

2 голосов
/ 29 июня 2010

Похоже, есть 4 варианта:
FromPerson -> ToPerson
FromPerson -> ToEmployee
FromEmployee -> ToPerson
FromEmployee -> ToEmployee

Итак, я бы предложил объединиться в 4 запроса и объединить результаты. Что-то вроде (при условии, что вы используете имена от и до для целей примера):

SELECT from.name from_name, to.name to_name<br> FROM Person from, PersonData pd, Person to<br> WHERE from.Id = pd.FromPersonId<br> AND to.Id = pd.ToPersonId<br> UNION<br> SELECT from.name from_name, to.name to_name<br> FROM Person from, PersonData pd, Employee to<br> WHERE from.Id = pd.FromPersonId<br> AND to.Id = pd.ToEmployeeId<br> UNION<br> ... (you get the picture)

1 голос
/ 29 июня 2010

Поскольку вы не опубликовали свою схему как SQL DDL, у меня возникают проблемы с просмотром, как эти таблицы могут работать на практике. Вот моя попытка:

Казалось бы, справедливое предположение, что работник должен быть человеком, так что это достаточно просто (угадывание типов данных и правил домена):

CREATE TABLE NaturalPersons
(
 PersonId INTEGER NOT NULL UNIQUE
);

CREATE TABLE Employees
(
 PersonId INTEGER NOT NULL UNIQUE
    REFERENCES NaturalPersons (PersonId), 
 EmployeeID CHAR(3) NOT NULL UNIQUE
    CHECK (EmployeeID LIKE '[A-Z][0-9][0-9]')
);

Имя таблицы «PersonData» мало что показывает, но из имен элементов данных кажется, что что-то передается от одного человека / сотрудника другому:

CREATE TABLE Transfers
(
 FromPersonId INTEGER 
    REFERENCES NaturalPersons (PersonId), 
 FromEmployeeID CHAR(3)
    REFERENCES Employees (EmployeeID),
 ToPersonId INTEGER 
    REFERENCES NaturalPersons (PersonId), 
 ToEmployeeID CHAR(3)
    REFERENCES Employees (EmployeeID)
);

Хм, все NULL способные столбцы означают, что у нас не может быть PRIMARY KEY, но мне интересно, есть ли вообще ключ ...?

Нам нужен только один тип идентификатора для «от» и «до» соответственно:

ALTER TABLE Transfers ADD
 CONSTRAINT only_one_from_ID
    CHECK (
           (FromPersonId IS NULL AND FromEmployeeID IS NOT NULL)
           OR
           (FromPersonId IS NOT NULL AND FromEmployeeID IS NULL)
          );

ALTER TABLE Transfers ADD
 CONSTRAINT only_one_to_ID
    CHECK (
           (ToPersonId IS NULL AND ToEmployeeID IS NOT NULL)
           OR
           (ToPersonId IS NOT NULL AND ToEmployeeID IS NULL)
          );

Мы также хотим, чтобы бизнес-правила «здравого смысла» предотвращали переводы от одного и того же лица / сотрудника:

ALTER TABLE Transfers ADD
 CONSTRAINT FromPersonId_cannot_be_ToPersonId
    CHECK (FromPersonId <> ToPersonId);

ALTER TABLE Transfers ADD
 CONSTRAINT FromEmployeeId_cannot_be_ToEmployeeId
    CHECK (FromEmployeeId <> ToEmployeeId);

Это лучшее, что мы можем сделать, но у нас есть пара проблем:

INSERT INTO NaturalPersons (PersonId) VALUES (1), (2), (3), (4);
INSERT INTO Employees (PersonId, EmployeeID) VALUES (1, 'A11'), (2, 'B22');

-- transfer to same entity - oops!:
INSERT INTO Transfers (FromPersonId, ToEmployeeID) VALUES (1, 'A11'); 

-- Duplicate transfer - oops!:
INSERT INTO Transfers (FromEmployeeId, ToPersonID) VALUES (1, 'B1'); -- duplicate
INSERT INTO Transfers (FromPersonId, ToEmployeeID) VALUES ('A1', 2); -- duplicate

Другими словами, смешивание PersonId и EmployeeID в одной таблице затрудняет написание основных правил данных.

Если я правильно понимаю, что работник - это человек, почему бы не использовать только PersonID?

Если сотрудник не человек, вы можете опубликовать свою схему (тип данных, ограничения и т. Д.), Пожалуйста?

1 голос
/ 29 июня 2010

Хорошо, похоже, проблема в том, что если вы присоединитесь к Person с FromPersonID = PersonID и ToPersonId = PersonID, вы получите 2 записи для каждой записи в PersonData.

Обойти это можно следующим образом:присоединитесь к двум псевдонимам PersonData, чтобы вы могли прикрепить результаты в одну строку.Что-то вроде:

Select * from PersonData
LEFT JOIN Person p1 on p1.PersonID = FromPersonID
LEFT JOIN Person p2 on p2.PersonID = ToPersonID

и в основном то же самое для полей сотрудника и из сотрудников

...