2016-05-19 43 views
1

私は、少なくとも1つの他の会社と共有する[会社]テーブルからすべての会社の行を選択しようとしています。 CompanyId列)、それぞれの従業員の各グループは、同一のLocationIds([従業員]テーブルの列)を同じ割合で共有します。類似のデータセットに関連付けられているオブジェクトの選択

したがって、たとえば、locationIds 1,2および2を持つ3人の従業員を持つ2つの企業が、このクエリによって選択されます。彼らは、少なくとも1つの他の企業に共通して共有するため

[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 

CompanyIds 1及び2が選択される:1。従業員数(3人の従業員) 2.その従業員に関連付けられたLocationIdの数/割合(LocationId 1を持つ従業員1人とLocationId 2を持つ従業員2人)。

これまでのところ、私はHAVING COUNT(?) > 1というステートメントを使用したいと思っていますが、詳細の作業には問題があります。誰にも何か提案はありますか?

+0

どのようにいくつかの詳細についてはどうですか?これは始めるのに最適な場所です。 http://spaghettidba.com/2015/04/24/how-to-post-a-t-sql-question-on-a-public-forum/ –

+0

あなたがここで何を求めているのかは分かりません。いくつかのサンプルデータと期待される出力が必要です。 – Chuck

+0

もっと明確でないことを申し訳ありません。私はいくつかの表を例として追加しました。 – fyodorfranz

答えて

1

これは醜いですが、私は考えることができる唯一の方法は、それを行うには:

;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) 

を参照してくださいフィドル:http://www.sqlfiddle.com/#!6/6bc16/5それはに場所データあたりの従業員の数(複数行)を符号化することによって動作します

各会社のxml文字列。

独自にCTEコード:

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 

のようなデータを生成します:

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"/> 

をそれからそれは(など、むしろ複数の行が一致するかどうかを確認しようとするよりも、)この文字列に基づいて企業を比較します。

+0

提案していただきありがとうございます!このスケールはうまくいくでしょうか?たとえば、約1000人の従業員を抱え、約10,000社の企業があるとします。このようなクエリは、約24時間で「半高性能条件」で実行できるでしょうか? – fyodorfranz

+0

私はそれが24時間近くのどこかにかかるとは期待していませんが、実際のデータでどのように実際の負荷がかかっているかを調べるためには、実際にテストする必要があります。 CTEデータはキャッシュされませんが、参照されるたびに実行されるため、おそらくここで改善する必要があります。たとえば、一時表を使用してCTEデータを格納することができます。 – Blorgbeard

+0

ありがとうございます、これはうまくいくように見えます。もう一つの最後の質問:従業員のいない会社の業績を排除する簡単な方法はありますか? – fyodorfranz

1

代わりの方法は次のようになります。ただし、事前にパフォーマンステストを行う必要があります(<>タイプ結合にはかなり自信が持てません)。

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 

関連フィドル:http://sqlfiddle.com/#!6/d9f2e/1

+0

直感的に言えば、あなたのソリューションは私のものよりも好きです。私はそれがより速くなることを期待し、 'xmlのために'はとにかく汚いと感じました。私は大規模なデータセットでパフォーマンスの比較を見て興味深いだろう! – Blorgbeard

+0

クイックアップデート:これは正式なパフォーマンステストではありませんが、 'for XML for'アプローチ(上記)は約30秒でデータセットを実行しましたが、約3分後にこの '<> join'をキャンセルしました。私は結果に少し驚いた。助けてくれてありがとう! – fyodorfranz

+1

私は驚いていないと思います。あなたが10,000人の顧客を抱えていて、それぞれの場所の数に多少のばらつきがない場合、残念ながら膨大な数の組み合わせが生成されます。 –

関連する問題