我正在使用SQL Server 2012并拥有以下表格:Ownership
,Property
,Person
表格Person
包含有关人名的信息,例如姓氏和姓氏,此表格中包含PersonId
作为主键。
表Property
包含有关属性的信息,例如属性区域,属性描述..此表格以PropertyId
为主键
因为每个人可以拥有多个属性,并且每个属性的所有权可以超过一个人,所以我们在Person
和Property
之间存在多对多关系
所以我创建了表Ownership
来打破这种关系,所以这个表有PersonId
和PropertyId
作为外键,以及以下列:PropertyId
as“Primary键“,StartDate
,EndDate
和OwnershipPercent
。
Start Date
和End Date
是指某人拥有该财产的时间段,而OwnershipPercent
是指该人在该财产中所占的份额。
现在我想编写一个查询,以便同时返回多个人拥有的任何属性超过100%
例如:
Id=1
属性属于#1从1-1-2010到1-1-2012的人,他在此属性中的份额为90%,此属性也属于另一个#2来自的人1-1-2010到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个总和,这是错误的
如何解决这个问题?
答案 0 :(得分: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?
一个关键的区别是此查询是在PropertyId和日期上聚合的。这是有道理的,因为所有权的数量会随着时间的推移而改变。
答案 1 :(得分: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;
答案 2 :(得分: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
答案 3 :(得分:0)
以下内容类似于@Gordon Linoff's suggestion,因为它还将范围列表“分解”为开始日期和结束日期列表。但是,它在结果列表中使用不同的技术。它还假设只有开始日期是包含性的,而结束日期则不是。
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
现在,您可以看到,在第一步,不显示原始表的每一行都被替换为两行,而且每个百分比值都被标记为增量(PercentFactor = 1
)或者递减(PercentFactor = -1
),取决于它是与起始日期一起出现还是与结束日期一起出现。因此,unpivoted
CTE评估以下结果集:
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
此时,我们的想法基本上是为每OwnershipPercent
计算每EventDate
个PropertyId
的运行总计,同时考虑该值是递增还是递减。 (事实上,你可以在第一阶段将标志合并到OwnershipPercent
而不是分配PercentFactor
的单独列。我选择后者更好地说明了这个想法,但应该没有表现如果你更喜欢前者,则会受到惩罚。)这就是你在计算总跑数(这是第二次CTE,summedup
之后)得到的结果:
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
您还可以查看(以及使用)此查询at SQL Fiddle。