SQL Получить первое поле, соответствующее некоторой указанной информации в ненормализованной таблице - PullRequest
1 голос
/ 28 ноября 2011

У меня есть таблица SQL, в которой я не могу изменить структуру.

Таблица Employee_Team состоит из 5 столбцов: TeamID, Employee1, Employee2, Employee3 и Employee4. Поля столбцов Employee1, Employee2, Employee3 и Employee4 содержат идентификатор EmployeeID. Каждый идентификатор сотрудника имеет город в таблице Employee. В одном ряду Employee_Team может быть несколько сотрудников, которые живут в одном городе. В городе, который я ищу, всегда будет хотя бы один сотрудник, который будет искать.

пример http://www.atriasoft.com/table.png

Пример:

Я хочу первого сотрудника, который живет в Нью-Йорке. В случае TeamID 01 это будет Employee2 (я не хочу Employee 4, хотя его город Нью-Йорк), а в случае TeamID 02 это будет Employee1 (я все еще не хочу, чтобы второй сотрудник живет в нью-йорке).

В настоящее время у меня есть код, который дает мне каждого сотрудника, который живет в Нью-Йорке:

SELECT * 
  FROM Employee_Team
 INNER JOIN Employees
    ON Employees.EmployeeID = Employee_Team.Employee1 OR
       Employees.EmployeeID = Employee_Team.Employee2 OR
       Employees.EmployeeID = Employee_Team.Employee3 OR
       Employees.EmployeeID = Employee_Team.Employee4
 WHERE Employees.City = ‘New York’

То, что я ищу, - это код, который принимает только первый сотрудник, живущий в Нью-Йорке. Любые намеки будут высоко оценены!

Ответы [ 3 ]

1 голос
/ 28 ноября 2011

Вы на самом деле можете безопасно "виртуально" изменить определение своей таблицы, используя ее в качестве основы для представления:

 CREATE VIEW NormalTeams (TeamID, EmployeeID, TeamMemberNumber) AS
     SELECT TeamID, Employee1, 1 FROM Employee_TEAM UNION ALL
     SELECT TeamID, Employee2, 2 FROM Employee_TEAM UNION ALL
     SELECT TeamID, Employee3, 3 FROM Employee_TEAM UNION ALL
     SELECT TeamID, Employee4, 4 FROM Employee_TEAM

Теперь NormalTeams позволит вам ВЫБРАТЬ данные так, как вы ожидаете:

 SELECT TeamID, MIN(TeamMemberNumber)
    FROM NormalTeams T INNER JOIN Employees E ON T.EmployeeiD = E.EmployeeID
    WHERE E.City = 'New York'
    GROUP BY TeamID

даст вам первый «номер» члена команды для Нью-Йорка.

 SELECT TeamID, City, MIN(TeamMemberNumber)
    FROM NormalTeams T INNER JOIN Employees E ON T.EmployeeiD = E.EmployeeID
    GROUP BY TeamID, City

даст вам более общее решение для каждой комбинации Город / Команда.

Вы можете присоединить эти результаты к NormalTeams, чтобы получить идентификатор сотрудника.

1 голос
/ 28 ноября 2011

CASE заявление должно быть вашим другом здесь:

SELECT et.TeamID
      ,CASE WHEN e1.City = c.city THEN e1.EmployeeID
            WHEN e2.City = c.city THEN e2.EmployeeID
            WHEN e3.City = c.city THEN e3.EmployeeID
            WHEN e4.City = c.city THEN e4.EmployeeID
            ELSE NULL
       END AS first_in_city
FROM  (SELECT 'New York' AS city) c    -- to parametrize the city we look for 
      ,Employee_Team et
LEFT   JOIN Employees e1 ON e1.EmployeeID = et.Employee1
LEFT   JOIN Employees e2 ON e2.EmployeeID = et.Employee2
LEFT   JOIN Employees e3 ON e3.EmployeeID = et.Employee3
LEFT   JOIN Employees e4 ON e4.EmployeeID = et.Employee4

То, что сделало ваш запрос разрушенным, заключается в следующем: вам нужно присоединиться к таблице Employees четыре раза, а не один раз. Как будто это будет четыре разных стола.
Я выбрал LEFT JOIN, поэтому мы не теряем строк, если ссылочная целостность не гарантируется.

0 голосов
/ 28 ноября 2011

Мне нравится unpivot, чтобы нормализовать структуру / таблицу, чтобы вы могли использовать ниже CTE для замены на View, чтобы не было никаких изменений определения, но задан параметр времени выполнения.

with team_cte(TeamID, EmployeeID, n)
as
(
    select TeamID, EmployeeID, row_number() over (partition by TeamID order by TeamID) as n
    from    
        (select TeamID, Employee1, Employee2, Employee3, Employee4 
         from Employee_Team) p
    UNPIVOT
    (   
        EmployeeID  
        FOR Employee in (Employee1, Employee2, Employee3, Employee4)
    ) AS unpvt
)
select TeamID, min(n) as FirstEmployeeID
from team_cte 
where EmployeeID in
(
    select EmployeeID from Employees where City = 'New York'
)
group by TeamID
...