2010-02-26 4 views
1

Voici ma déclaration select avec la innerjoin de deux tables,Quel est le problème avec ce sql innerjoin?

if not exists(select EmpId from SalaryDetails 
       where EmpId in (select Emp_Id 
           from Employee where [email protected])) 
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 

Mon volet de résultats,

alt text http://img220.imageshack.us/img220/7774/resultpane.jpg

Et Mon SalaryDetails Table,

alt text http://img28.imageshack.us/img28/770/salarydettable.jpg

EDIT : Ma sortie doit être,

16 CR14 Natarajan semaine 150,00 354,00
17 cr12333 Pandian hebdomadaire 122,00 0,00

+1

Il pourrait aider si vous nous avez donné une idée de ce qui ne va pas avec votre sortie. Je ne peux pas comprendre, et je ne suis pas prêt à le faire. –

+1

@Lieven, était sur le point de faire le même commentaire - J'ai fait une estimation qu'il obtient toujours 354 pour l'Advance alors qu'il a des valeurs différentes dans les détails Salary - je pourrais être loin de la marque, cependant. –

+0

Vous avez raison, mais cela n'a rien à voir avec les jointures internes. –

Répondre

2

Il semble que votre jointure à Designation ne soit même pas utilisée et que vous manquiez également votre clause WHERE que vous avez utilisée dans l'instruction IF en haut. Je déplacerais aussi la sous-requête dans la jointure comme Andy l'a fait remarquer. Sans avoir le DB à tester contre cela, ce ne sera probablement pas exact mais je le réécrirais à quelque chose comme;

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 [email protected] 

suggestion de Andy pour déplacer le sous-requête en vue est un bon, beaucoup plus facile à lire et probablement beaucoup plus efficace si la base de données est grande.

EDIT: (REPONSE)

(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 

J'ai modifié la réponse de jay parce qu'il est venu près de ma sortie ...

+0

Juste un pourboire Jay, votre TOP 1 dans le La sous-requête va être appliquée avant l'EmpID dans la jointure, donc si vous avez 2 enregistrements dans SalaryDetails avec EmpID 16 et 17 avec 16 étant le premier lorsqu'il est trié par CreatedDesc, et votre jointure a un e.Emp_Id de 17, il ne sera pas correspond à la requête SELECT TOP 1 .... Je suis tombé pour cette erreur avant - il n'a pas été remarqué jusqu'à environ 6 mois plus tard, oups! Vous devez utiliser RANK() pour obtenir le TOP 1 par ID d'employé. –

+0

@ Jay13 cela fonctionne pour moi ... Mais je reçois seulement une rangée .... Mon categoryId donne deux empIds '16,17' ... –

3

Vous n'êtes pas filtrer la sous-requête (SELECT TOP 1 RemainingAdvance FROM SalaryDetails ORDER BY CreatedDate DESC) sur un ID d'employé, de sorte il vous donne le premier enregistrement dans le tableau entier quand trié par CreatedDate DESC (que je devine est 354.)

Vous voudrez probablement déplacer cette expression de table dans votre clause FROM, pas votre SELECT, inclure votre ID d'employé et fais un rejoindre sur cette expression.

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 

Ceci est juste sur le dessus de ma tête, donc peut-être un peu de peaufiner pour fonctionner correctement. Notez également l'utilisation de la fonction RANK() - si vous utilisez TOP 1, vous obtenez uniquement le premier enregistrement de la table entière. Ce dont vous avez besoin est le premier enregistrement par employé ID. Si c'était moi, je ferais probablement de cette expression une vue ou même une fonction scalaire en prenant votre ID employé et en retournant la première valeur RemainingAdvance, alors vous pourriez utiliser TOP 1 et filtrer sur l'ID employé.

+0

@Andy regarde ma déclaration si non existe il reurn deux employés Id's 16,17 –

+0

+1 À la lumière de ne pas savoir ce qui est réellement faux, c'est la meilleure estimation que je suppose. –

+0

@Andy pouvez-vous modifier une vue pour moi dans votre réponse ... –