Что не так с этим sql innerjoin? - PullRequest
       18

Что не так с этим sql innerjoin?

1 голос
/ 26 февраля 2010

Вот мое утверждение select с внутренним объединением двух таблиц,

if not exists(select EmpId from SalaryDetails 
              where EmpId in (select Emp_Id 
                              from Employee where Desig_Id=@CategoryId))
begin
  // some statements here
end
else
begin
  SELECT e.Emp_Id, e.Identity_No, e.Emp_Name,
      case WHEN e.SalaryBasis=1 THEN 'Weekly' 
           ELSE 'Monthly' end as SalaryBasis,e.FixedSalary,
      (SELECT TOP 1 RemainingAdvance 
       FROM SalaryDetails 
       ORDER BY CreatedDate DESC) as Advance
    FROM Employee as e inner join Designation as d on e.Desig_Id=d.Desig_Id 
    INNER JOIN SalaryDetails as S on e.Emp_Id=S.EmpId 
End

Панель моих результатов,

альтернативный текст http://img220.imageshack.us/img220/7774/resultpane.jpg

И моя таблица зарплатных данных,

альтернативный текст http://img28.imageshack.us/img28/770/salarydettable.jpg

EDIT: Мой вывод должен быть,

16 CR14 Natarajan Еженедельно 150,00 354,00
17 cr12333 Pandian Weekly 122,00 0,00

Ответы [ 2 ]

3 голосов
/ 26 февраля 2010

Вы не фильтруете подзапрос (SELECT TOP 1 RemainingAdvance FROM SalaryDetails ORDER BY CreatedDate DESC) по любому идентификатору сотрудника, поэтому он дает вам первую запись во всей таблице при сортировке по CreatedDate DESC (что, я предполагаю, равно 354).

Возможно, вы захотите переместить это табличное выражение в ваше предложение FROM, а не в SELECT, включить свой идентификатор сотрудника и выполнить соединение с этим выражением.

SELECT 
    e.Emp_Id,e.Identity_No,e.Emp_Name,case WHEN e.SalaryBasis=1 THEN 'Weekly' ELSE 'Monthly' end as SalaryBasis,e.FixedSalary,
    from Employee as e inner join Designation as d on e.Desig_Id=d.Desig_Id 
    inner join SalaryDetails as S on e.Emp_Id=S.EmpId 
    inner join
    (SELECT EmpID, RemainingAdvance, RANK() OVER (PARTITION BY EmpID ORDER BY CreatedDate DESC) AS SalaryRank FROM SalaryDetails ORDER BY CreatedDate DESC) as Advance ON Advance.EmpID = e.Emp_ID AND Advance.SalaryRank = 1

Это только от макушки моей головы, поэтому для корректной работы может потребоваться небольшая настройка. Обратите внимание также на использование функции RANK () - если вы используете TOP 1, вы получите только первую запись всей таблицы. Вам нужна первая запись на сотрудника ID .

Если бы это был я, я, вероятно, сделал бы это табличное выражение представлением или даже скалярной функцией, принимающей идентификатор сотрудника и возвращающей первое значение RemainingAdvance, тогда вы могли бы использовать TOP 1 и отфильтровать идентификатор сотрудника.

2 голосов
/ 26 февраля 2010

Похоже, что ваше присоединение к Designation даже не используется, и вы также пропускаете предложение WHERE, которое вы использовали в операторе IF в верхней части. Я также переместил бы подзапрос в соединение, как указал Энди. Без БД, чтобы проверить это, вероятно, не будет точным, но я бы переписал что-то вроде:

SELECT e.Emp_Id, e.Identity_No, e.Emp_Name,
  case WHEN e.SalaryBasis=1 
       THEN 'Weekly' 
       ELSE 'Monthly' end as SalaryBasis,
  e.FixedSalary,S.RemainingAdvance as Advance
FROM Employee as e 
  INNER JOIN (
   SELECT TOP 1 EmpId, RemainingAdvance 
   FROM SalaryDetails 
   ORDER BY CreatedDate DESC) as S on e.Emp_Id=S.EmpId 
WHERE e.Desig_Id=@CategoryId

Предложение Энди переместить подзапрос в представление является хорошим, его легче читать и, возможно, намного эффективнее, если база данных велика.

РЕДАКТИРОВАТЬ: (ОТВЕТ)

(SELECT sd.empid,
               sd.remainingadvance,
               ROW_NUMBER() OVER (PARTITION BY sd.empid ORDER BY sd.createddate DESC) AS rank
          FROM SALARYDETAILS sd
          JOIN EMPLOYEE e ON e.emp_id = sd.empid
                         AND e.desig_id = @CategoryId) s
            WHERE s.rank = 1

Я отредактировал ответ Джея, потому что он подошел к моему выводу ...

...