我使用动态属性来管理个人的特征。我有一个表IndividusDynPropValues,每个人和每个属性都有1行,例如:
ID StartDate ValueString ValueFloat ValueDate Individus_ID IndividusDynProp
14 2018-09-10 Outside NULL NULL 3 Out Status
13 2018-08-15 Dead NULL NULL 1 Out Status
12 2018-08-02 Male NULL NULL 3 Sex
11 2018-07-28 #DBNULL# NULL NULL 1 Out Status
10 2018-07-25 Sold NULL NULL 1 Out Status
9 2018-06-07 Unk NULL NULL 3 Sex
8 2018-06-07 Adult NULL NULL 3 Status
7 2018-06-06 Femal NULL NULL 2 Sex
6 2018-06-06 Adult NULL NULL 2 Status
5 2018-06-03 Male NULL NULL 1 Sex
4 2018-06-03 Adult NULL NULL 1 Status
3 2018-05-23 Egg NULL NULL 3 Status
2 2018-05-23 Egg NULL NULL 2 Status
1 2018-05-21 Egg NULL NULL 1 Status
“#DBNULL#”表示此人再次在现场。我想创建一个函数,该函数为输入参数添加一个日期,并返回一个表,其中包含该日期“属于现场居住的男性”群体的每个人的ID。如果Sex ='Male'AND(Out Status IS NULL或Out Status ='#DBNULL#'),则个人属于该组。 因此,在示例中,如果在函数中输入的日期为“ 2018-07-20”,则返回:
Individus_ID
1
如果日期为“ 2018-08-10”,则返回:
Individus_ID
3
1
如果日期为“ 2018-08-17”,则返回:
Individus_ID
3
我尝试过:
CREATE FUNCTION fn_Groupe_Individus_Male_Vivant (@daDate datetime)
RETURNS @TGrMalesVivants TABLE (
TList_Individual [varchar] (50) NOT NULL
)
AS
BEGIN
DECLARE @TtempGrMalesVivants TABLE (TList_Individual [varchar] (50) NOT NULL)
DECLARE @TtempGrMales TABLE (TList_MIndividual int NOT NULL)
INSERT INTO @TtempGrMales
SELECT DISTINCT Individus_ID
FROM IndividusDynPropValues
DECLARE @selectedOutStatus VARCHAR(50),
@sBirdId int,
@tmpSex VARCHAR(3)
WHILE EXISTS (SELECT * FROM @TtempGrMales)
BEGIN
SELECT TOP 1 @sBirdId = TList_MIndividual FROM @TtempGrMales
SELECT @selectedOutStatus =IDPV.ValueString
FROM [dbo].[IndividusDynPropValues] AS IDPV
WHERE NOT EXISTS (SELECT *
FROM [dbo].[IndividusDynPropValues] AS IDPV2
WHERE IDPV.Individus_ID=IDPV2.Individus_ID
AND IDPV.IndividusDynProp_ID=IDPV2.IndividusDynProp_ID
AND IDPV2.StartDate>IDPV.StartDate AND CONVERT(smalldatetime,IDPV2.StartDate,120 )<=@daDate)
AND CONVERT(smalldatetime,IDPV.StartDate,120 )<=@daDate
AND IDPV.Individus_ID =@sBirdId
AND IDPV.IndividusDynProp_ID='Out Status'
SELECT @tmpSex= IDPV.ValueString
FROM [dbo].[IndividusDynPropValues] AS IDPV
INNER JOIN TSaisie AS TS ON TS.TSai_PK_ID=IDPV.Saisie_ID
INNER JOIN TProtocole AS TP ON TP.TPro_PK_ID=TS.TSai_FK_TPro_ID
WHERE NOT EXISTS (SELECT *
FROM [dbo].[IndividusDynPropValues] AS IDPV2
WHERE IDPV.Individus_ID=IDPV2.Individus_ID
AND IDPV.IndividusDynProp_ID=IDPV2.IndividusDynProp_ID
AND IDPV2.StartDate>IDPV.StartDate AND CONVERT(smalldatetime,IDPV2.StartDate,120 )<=@daDate)
AND CONVERT(smalldatetime,IDPV.StartDate,120 )<=@daDate
AND IDPV.Individus_ID =@sBirdId
AND IDPV.IndividusDynProp_ID='Sex'
AND TPro_Importance = (SELECT Max(TP2.Tpro_Importance)
FROM IndividusDynPropValues IDPV3
INNER JOIN TSaisie AS TS2 ON TS2.TSai_PK_ID=IDPV3.Saisie_ID
INNER JOIN TProtocole AS TP2 ON TP2.TPro_PK_ID=TS2.TSai_FK_TPro_ID
WHERE IDPV3.Individus_ID=@sBirdId
AND IDPV3.IndividusDynProp_ID=4
AND IDPV3.StartDate>=IDPV.StartDate
AND CONVERT(smalldatetime,IDPV3.StartDate,120 )<=@daDate)
IF @tmpSex='Male' AND (@selectedOutStatus IS NULL OR @selectedOutStatus='#DBNULL#')
BEGIN
INSERT INTO @TtempGrMalesVivants (TList_Individual)
VALUES (@sBirdId)
END
DELETE TOP (1) FROM @TtempGrMales
END
INSERT @TGrMalesVivants
SELECT *
FROM @TtempGrMalesVivants
RETURN
END
它可以工作,但所有表格(1859732行)都需要1:55,所以太长了
答案 0 :(得分:0)
我想我了解您正在尝试做什么。请注意我如何发布样本数据?这是您将来应该做的一个很好的例子。
一些条件聚合应该在这里起作用。您需要这种聚合,因为您的数据已被规范化为EAV,并且需要将其重组为规范化表。这适用于示例数据和所需的输出。您可以取消注释设置的@MyDate行,以查看第二个值是否起作用。
if OBJECT_ID('tempdb..#IndividusDynPropValues') is not null
drop table #IndividusDynPropValues
create table #IndividusDynPropValues
(
ID int
, StartDate date
, ValueString varchar(50)
, ValueFloat float
, ValueDate date
, Individus_ID int
, IndividusDynProp varchar(50)
)
insert #IndividusDynPropValues values
(14, '2018-09-10', 'Outside', NULL, NULL, 3, 'Out Status')
, (13, '2018-08-15', 'Dead', NULL, NULL, 1, 'Out Status')
, (12, '2018-08-02', 'Male', NULL, NULL, 3, 'Sex')
, (11, '2018-07-28', '#DBNULL#', NULL, NULL, 1, 'Out Status')
, (10, '2018-07-25', 'Sold', NULL, NULL, 1, 'Out Status')
, (9 , '2018-06-07', 'Unk' , NULL, NULL, 3, 'Sex')
, (8 , '2018-06-07', 'Adult' , NULL, NULL, 3, 'Status')
, (7 , '2018-06-06', 'Femal' , NULL, NULL, 2, 'Sex')
, (6 , '2018-06-06', 'Adult' , NULL, NULL, 2, 'Status')
, (5 , '2018-06-03', 'Male' , NULL, NULL, 1, 'Sex')
, (4 , '2018-06-03', 'Adult' , NULL, NULL, 1, 'Status')
, (3 , '2018-05-23', 'Egg' , NULL, NULL, 3, 'Status')
, (2 , '2018-05-23', 'Egg' , NULL, NULL, 2, 'Status')
, (1 , '2018-05-21', 'Egg' , NULL, NULL, 1, 'Status')
declare @MyDate date = '20180720' --returns Individus_ID 1
--set @MyDate = '20180810' --returns Individus_ID 1, 3
;
with MySortedData as
(
select i.*
, RowNum = ROW_NUMBER()over(partition by i.Individus_ID, i.IndividusDynProp order by i.StartDate desc)
from #IndividusDynPropValues i
where i.StartDate <= @MyDate
)
select s.Individus_ID
, OutStatus = max(case when IndividusDynProp = 'Out Status' then ValueString end)
, Status = max(case when IndividusDynProp = 'Status' then ValueString end)
, Sex = max(case when IndividusDynProp = 'Sex' then ValueString end)
from MySortedData s
where s.RowNum = 1
group by s.Individus_ID
having isnull(max(case when IndividusDynProp = 'Out Status' then ValueString end), '#DBNULL#') = '#DBNULL#'
and max(case when IndividusDynProp = 'Sex' then ValueString end) = 'Male'