Sélection d'objects associés à des sets de données similaires

J'essaie de sélectionner toutes les lignes de la société d'une table [Société] partageant avec au less une autre société, le même nombre d'employés (à partir d'une table [Employee] avec une colonne CompanyId), où chaque groupe d'employés le même set de LocationIds (une colonne dans la table [Employee]) et dans la même proportion.

Ainsi, par exemple, deux entresockets avec trois employés ayant chacune les locations location 1,2 et 2 seraient sélectionnées par cette requête.

[Employee] EmployeeId | CompanyId | LocationId | ======================================== 1 | 1 | 1 2 | 1 | 2 3 | 1 | 2 4 | 2 | 1 5 | 2 | 2 6 | 2 | 2 7 | 3 | 3 [Company] CompanyId | ============ 1 | 2 | 3 | Returns the CompanyIds: ====================== 1 2 

Les numéros d'entreprise 1 et 2 sont sélectionnés parce qu'ils ont en commun avec au less une autre entreprise: 1. le nombre d'employés (3 employés); et 2. le nombre / la proportion de LocationIds associés à ces employés (1 employé a LocationId 1 et 2 employés ont LocationId 2).

Jusqu'à présent, je pense que je veux utiliser une déclaration HAVING COUNT(?) > 1 , mais j'ai du mal à travailler sur les détails. Est-ce que quelqu'un a des suggestions?

C'est moche, mais la seule façon dont je peux penser à le faire:

 ;with CTE as ( select c.Id, ( select e.Location, count(e.Id) [EmployeeCount] from Employee e where e.IdCompany=c.Id group by e.Location order by e.Location for xml auto ) LocationEmployeeData from Company c ) select c.Id from Company c join ( select x.LocationEmployeeData, count(x.Id) [CompanyCount] from CTE x group by x.LocationEmployeeData having count(x.Id) >= 2 ) y on y.LocationEmployeeData = (select LocationEmployeeData from CTE where Id = c.Id) 

Voir violon: http://www.sqlfiddle.com/#!6/6bc16/5

Il fonctionne en encodant le nombre d'employés par location (plusieurs lignes) dans une string xml pour chaque société.

Le code CTE seul:

 select c.Id, ( select e.Location, count(e.Id) [EmployeeCount] from Employee e where e.IdCompany=c.Id group by e.Location order by e.Location for xml auto ) LocationEmployeeData from Company c 

Produit des données comme:

 Id LocationEmployeeData 1 <e Location="1" EmployeeCount="2"/><e Location="2" EmployeeCount="1"/> 2 <e Location="1" EmployeeCount="2"/><e Location="2" EmployeeCount="1"/> 3 <e Location="3" EmployeeCount="1"/> 

Ensuite, il compare les entresockets basées sur cette string (plutôt que d'essayer de déterminer si plusieurs lignes correspondent, etc.).

Une solution alternative pourrait ressembler à ceci. Cependant, il faut également tester les performances à l'avance (je ne me sens pas très à l'aise avec <> type join).

 with List as ( select IdCompany, Location, row_number() over (partition by IdCompany order by Location) as RowId, count(1) over (partition by IdCompany) as LocCount from Employee ) select A.IdCompany from List as A inner join List as B on A.IdCompany <> B.IdCompany and A.RowID = B.RowID and A.LocCount = B.LocCount group by A.IdCompany, A.LocCount having sum(case when A.Location = B.Location then 1 else 0 end) = A.LocCount 

Fiddle connexe: http://sqlfiddle.com/#!6/d9f2e/1