4

私は SQL Server 2012 を使用しており、次のテーブルがありOwnershipますPropertyPerson

テーブルPersonには、名、姓などの人に関する情報が保持され、このテーブルはPersonId主キーとして持っています。

このテーブルPropertyには、プロパティ エリア、プロパティの説明などのプロパティに関する情報が保持され、このテーブルにはPropertyId主キーとして

各人は複数のプロパティを持つことができ、プロパティの各所有者は複数の人である可能性があるため、 と の間には多対多の関係がPersonあります。Property

そこでOwnership、この関係を壊すためにテーブルを作成したので、このテーブルには外部キーとして と があり、「主キー」として 、 、および のPersonId列があります。PropertyIdPropertyIdStartDateEndDateOwnershipPercent

Start DateEnd Dateは、財産が誰かによって所有されている期間をOwnershipPercent指し、とは、その人の所有する財産の割合を指します。

次に、複数の人が同時に 100% 以上所有しているプロパティを返すクエリを作成します。

例えば:

の財産はId=1、2010 年 1 月 1 日から 2012 年 1 月 1 日まで #1 を持つ人に属し、この財産の彼のシェアは 90% であり、この財産は 2010 年 1 月 1 日から 1- 1-2012 で、このプロパティの彼のシェアは 80% です..同時に 90+80=170% を合計すると、これは間違っています (同時に 100% 未満になるため)。

次のクエリを書きました。

SELECT A.PropertyId
FROM Ownership A INNER JOIN Ownership B
ON a.PersonId <> b.PersonId
AND A.PropertyId = B.PropertyId
AND A.StartDate <= B.EndDate
AND A.EndDate >= B.StartDate
group by A.PropertyId
Having (sum(A.OwnershipPercent)) <=100; 

しかし、5 人に属するプロパティがある場合、(5×4)=20 の合計になり、これは間違っています。

これを修正するには?

4

4 に答える 4

2

所有権テーブルでの結合のアプローチは完全には正しくないと思います。あなたがやろうとしていることはわかりますが、参加すると所有者のペアが作成されます。代わりに、所有者のセットについて考えたいと思います。

私のアプローチは、各プロパティのすべての重要な日付を含むテーブルを作成することです。これは、OwnerShipテーブルのStartDateとEndDateになります。次に、これらの日付の所有率を見てみましょう。

select os.PropertyId, thedate, SUM(os.OwnershipPercent)
from ((select PropertyId, StartDate as thedate
       from ownership
      )union
      (select PropertyId, EndDate
       from ownership
      )
     ) driver join
     OwnerShip os
     on driver.PropertyId = os.PropertyId and
        driver.thedate between os.StartDate and os.EndDate
group by os.PropertyId, thedate
having SUM(os.OwnershipPercent) <= 100  -- Do you really want > 100 here?

主な違いの1つは、このクエリがPropertyIdと日付を集計していることです。所有権の量は時間の経過とともに変化する可能性があるため、これは理にかなっています。

于 2013-01-02T15:03:33.903 に答える
1

DISTINCT正しく行います、

SELECT A.PropertyId
FROM Ownership A INNER JOIN Ownership B
ON a.PersonId <> b.PersonId
AND A.PropertyId = B.PropertyId
AND A.StartDate <= B.EndDate
AND A.EndDate >= B.StartDate
group by A.PropertyId
Having (sum(distinct A.OwnershipPercent)) <=100; 
于 2013-01-02T12:54:39.837 に答える
0

以下は、範囲のリストを開始日と終了日のリストに「分解」するという点で、@Gordon Linoff の提案に似ています。ただし、結果のリストでは別の手法を使用します。また、開始日のみが含まれ、終了日は含まれないと想定しています。

WITH unpivoted AS (
  SELECT
    PropertyId,
    EventDate,
    OwnershipPercent,
    PercentFactor = CASE EventDateType WHEN 'EndDate' THEN -1 ELSE 1 END
  FROM Ownership
  UNPIVOT (
    EventDate FOR EventDateType IN (StartDate, EndDate)
  ) u
)
, summedup AS (
  SELECT DISTINCT
    PropertyId,
    EventDate,
    TotalPercent = SUM(OwnershipPercent * PercentFactor)
                   OVER (PARTITION BY PropertyId ORDER BY EventDate)
  FROM unpivoted
)
SELECT
  s.EventDate,
  s.TotalPercent,
  o.PropertyId,
  o.PersonId,
  o.StartDate,
  o.EndDate,
  o.OwnershipPercent
FROM summedup s
  INNER JOIN Ownership o
     ON s.PropertyId = o.PropertyId
    AND s.EventDate >= o.StartDate
    AND s.EventDate <  o.EndDate
WHERE TotalPercent > 100  -- changed from the original "<= 100"
                          -- based on the verbal description
;

これがどのように機能するかを説明するために、の内容をOwnership次のように仮定します。

PropertyId PersonId StartDate  EndDate    OwnershipPercent
---------- -------- ---------- ---------- ----------------
1          1        2010-01-01 2012-01-01 80
1          2        2011-01-01 2011-03-01 20
1          3        2011-02-01 2011-04-01 10
1          4        2011-05-01 2011-07-01 40

ここで、ピボットを解除する最初のステップで、元のテーブルのすべての行が 2 つの行に置き換えられるだけでなく、すべてのパーセント値が増分 ( PercentFactor = 1) または減分 ( PercentFactor = -1)としてマークされていることがわかります。開始日または終了日とともに表示されます。したがって、unpivotedCTE は次の結果セットに評価されます。

PropertyId EventDate  OwnershipPercent PercentFactor
---------- ---------- ---------------- -------------
1          2010-01-01 80               1
1          2011-01-01 20               1
1          2011-02-01 10               1
1          2011-03-01 20               -1
1          2011-04-01 10               -1
1          2011-05-01 40               1
1          2011-07-01 40               -1
1          2012-01-01 80               -1

この時点で、基本的には、値が増加するか減少するかを考慮して、OwnershipPercentat every EventDatefor everyの実行中の合計を計算します。(実際には、 の別の列を割り当てる代わりに、最初の段階でPropertyId符号を に組み込むことができます。アイデアをよりよく説明するために後者を選択しましたが、前者を好む場合、パフォーマンスのペナルティはないはずです。)は、実行中の合計を計算した後に得られるものです (これは、2 番目の CTE が行うことです)。OwnershipPercentPercentFactorsummedup

PropertyId EventDate  TotalPercent
---------- ---------- ------------
1          2010-01-01 80
1          2011-01-01 100
1          2011-02-01 110
1          2011-03-01 90
1          2011-04-01 80
1          2011-05-01 120
1          2011-07-01 80
1          2012-01-01 0

ただし、この結果のセットには重複する行が含まれる場合があることに注意してください。特に、同じPropertyIdに対して、一部の範囲が同時に開始または終了する場合、または一部の範囲が別の範囲の開始日に正確に終了する場合は、この問題が発生します。そのため、この段階で DISTINCT が使用されていることがわかります。

重要な日付の合計パーセント値がわかったので、100 を超えないものを除外し、残りを結合しOwnershipて、取得した合計に寄与する所有権の詳細にアクセスできます。したがって、メイン クエリの最終結果は次のようになります。

EventDate  TotalPercent PropertyId PersonId StartDate  EndDate    OwnershipPercent
---------- ------------ ---------- -------- ---------- ---------- ----------------
2011-02-01 110          1          1        2010-01-01 2012-01-01 80
2011-02-01 110          1          2        2011-01-01 2011-03-01 20
2011-02-01 110          1          3        2011-02-01 2011-04-01 10
2011-05-01 120          1          1        2010-01-01 2012-01-01 80
2011-05-01 120          1          4        2011-05-01 2011-07-01 40

SQL Fiddle でこのクエリを確認する (および操作する) こともできます。

于 2013-01-03T10:29:12.947 に答える
0

このリクエストはおそらくあなたにとって必要です

SELECT PropertyID,
FROM dbo.Ownership
GROUP BY PropertyID, StartDate, EndDate
HAVING COUNT(PersonID) > 1 
  AND SUM(OwnershipPercent) <= 100 --in your question you want > 100
于 2013-01-02T15:44:38.097 に答える