选择在给定日期具有某些属性的所有个人

时间:2019-06-03 13:34:23

标签: sql-server tsql

我使用动态属性来管理个人的特征。我有一个表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,所以太长了

1 个答案:

答案 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'