开发者

How to pass dynamic filters into stored procedure with paging

I have a stored procedure that gets a list of items, sorts and applies paging.

However I also need to add filtering. So what I want to do is pass in a string of filters like "27='Some Company';32='Auckland'", and split it into a temp table (see below split code)

Proposed Split code

 CREATE TABLE #Filters 
    (       
        ModelEntityId int not null, 
        ValueText nvarchar(max)
    ) 

    WHILE (@pos <> 0)
    BEGIN
        SET @NextFilter = substring(@Filters,1,@Pos - 1)
        SET @SubPos = charindex('=',@NextFilter)

        insert into #Filters (ModelEntityId, ValueText) 
                Values (substring(@NextFilter, 1, @SubPos-1),
                        substring(@NextFilter,@subPos+1, len(@NextFilter))) 

        SET @Filters = substring(@Filters,@pos+1,len(@Filters))
        SET @pos = charindex('~',@Filters)
    END

My Data is stored in a very generic way so one 'record' might look like this

ContainerModelEntityId DataContainerId ModelEntityId ValueText
4                      17              5             'sunshine company'
4                      17              6             '12999'
4                      17              7             '01/12/2010'
...
4                      18              5             'moonlight company...  
  • ContainerModelEntityId is the container type (i.e. business, person, etc)
  • DataContainerId is the 'row'
  • ModelEntityId is the 'field'
  • ValueText is the actual value

Currently the sp below has a SortFieldId that is passed into into it, and lets say that is a 5, I then do a join on my data table and sort where the ModelEntityId = 5. However now I also want to do a join on the values in my #filter table and only return results where the values match (I have placed a comment in the code below to show where I think the logic should go). But at this point I have blown my mind, as set logic usually gives me a headache. Any help appreciated.

Current Stored Procedure

   ALTER PROCEDURE [dbo].[GetSortedIndex]   
        @ContainerModelEntityId int,
        @ParentRecordId         int,
        @SortFieldId            int,
        @PageIndex              int,
        @PageSize               int,
        @Ascending              bit 
    AS
    BEGIN
        -- SET NOCOUNT ON added to pre开发者_运维知识库vent extra result sets from
        -- interfering with SELECT statements.
        SET NOCOUNT ON;

        CREATE TABLE #SelectedRecords 
        (       
            ContainerModelEntityId int not null, 
            DataContainerId int not null,
            DataInstanceId int not null,
            ParentDataContainerId int null 
        ) 

        DECLARE @LowerBound int, @UpperBound int

        -- Pagination   
        select @LowerBound = ((@PageIndex) * @PageSize)+1
        select @UpperBound = (@PageIndex+1) * @PageSize+1

        IF @Ascending = 1 
        BEGIN
            INSERT INTO #SelectedRecords
            SELECT ContainerModelEntityId, 
                           DataContainerId, 
                           DataInstanceId, 
                           ParentDataContainerId 
                    FROM
            ( 
                select di.ModelEntityId as 'ContainerModelEntityId',
                          dc.DataContainerId,
                          di.DataInstanceId, 
                          dv.ModelEntityId, 
                          dc.ParentDataContainerId,
                  ROW_NUMBER() OVER (ORDER BY dv.ValueText) AS row 
                from datacontainer dc
                inner join dataInstance di 
                           on dc.DataContainerId = di.DataContainerId
                        //some funky join on #Filter table to go here
                        left outer join dataValue dv 
                          on di.DataInstanceId = dv.DataInstanceId 
                          and dv.ModelEntityId=@SortFieldId
                where ISNULL(dc.ParentDataContainerId,0) 
                               = ISNULL(@ParentRecordId,0) 
                          and di.IsCurrent = 1 
                          and di.ModelEntityId = @ContainerModelEntityId
            ) tbl
                WHERE tbl.row >= @LowerBound AND
              tbl.row < @UpperBound
    END
    ELSE
    BEGIN
        INSERT INTO #SelectedRecords
        SELECT ContainerModelEntityId, DataContainerId, 
               DataInstanceId, ParentDataContainerId 
        FROM
        ( 
            select di.ModelEntityId as 'ContainerModelEntityId', 
                dc.DataContainerId, di.DataInstanceId, 
                dv.ModelEntityId, dc.ParentDataContainerId, dv.ValueText,
            ROW_NUMBER() OVER (ORDER BY dv.ValueText DESC) AS row 
        from datacontainer dc
        inner join dataInstance di 
                on dc.DataContainerId = di.DataContainerId
            //some funky join on #Filter table to go here
        left outer join dataValue dv 
                on di.DataInstanceId = dv.DataInstanceId 
                   and dv.ModelEntityId=@SortFieldId 
        where ISNULL(dc.ParentDataContainerId,0) = ISNULL(@ParentRecordId,0) 
                  and di.IsCurrent = 1 
                  and di.ModelEntityId=@ContainerModelEntityId 
        ) tbl
        WHERE tbl.row >= @LowerBound AND
              tbl.row < @UpperBound 
    END

    DECLARE @Count int
    SELECT @Count = (SELECT COUNT(*) FROM DataContainer dc
    INNER JOIN DataInstance di ON di.DataContainerId = dc.DataContainerId
    WHERE di.ModelEntityId = @ContainerModelEntityId 
     AND ISNULL(dc.ParentDataContainerId,0) = ISNULL(@ParentRecordId,0) 
     AND di.IsCurrent=1)

    SELECT ContainerModelEntityId, DataContainerId, 
           ParentDataContainerId, 
           isnull(dv.ModelEntityId, @sortFieldId) as 'ModelEntityId', 
           dv.ValueText, 
           @Count [TotalRecords] 
    FROM #SelectedRecords sr  
    left outer join dataValue dv ON sr.DataInstanceId = dv.DataInstanceId

END


OK, got something going now

ALTER PROCEDURE [dbo].[GetSortedIndex]  
@ContainerModelEntityId int,
@ParentRecordId         int,
@SortFieldId            int,
@PageIndex              int,
@PageSize               int,
@Ascending              bit = 1,
@Filters                varchar(max) = null 

AS BEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. SET NOCOUNT ON;

DECLARE @NextFilter NVARCHAR(100)
DECLARE @Pos INT
DECLARE @SubPos INT
DECLARE @NextPos INT

CREATE TABLE #Filters 
(       
    ModelEntityId int not null, 
    ValueText nvarchar(max)
) 

CREATE TABLE #SelectedRecords 
(   row int,    
    ContainerModelEntityId int not null, 
    DataContainerId int not null,
    DataInstanceId int not null,
    ParentDataContainerId int null 
) 

DECLARE @LowerBound int, @UpperBound int

-- Pagination   
select @LowerBound = ((@PageIndex) * @PageSize)+1
select @UpperBound = (@PageIndex+1) * @PageSize+1

IF (Len(@Filters)>0)
BEGIN
    SET @Filters = @Filters + '~'
    SET @Pos = charindex('~',@Filters)
    WHILE (@pos <> 0)
    BEGIN
        SET @NextFilter = substring(@Filters,1,@Pos - 1)
        SET @SubPos = charindex('=',@NextFilter)
        insert into #Filters (ModelEntityId, ValueText) Values (substring(@NextFilter, 1, @SubPos-1),substring(@NextFilter,@subPos+1, len(@NextFilter))) 
        SET @Filters = substring(@Filters,@pos+1,len(@Filters))
        SET @pos = charindex('~',@Filters)
    END     

    INSERT INTO #SelectedRecords    
        select  row,
               ContainerModelEntityId,
               DataContainerId, 
               DataInstanceId,
               ParentDataContainerId           
        from
        (
            select row_number() over (order by dv.valuetext) as row,
                   filtered.ContainerModelEntityId,
                   filtered.ParentDataContainerId, 
                   filtered.DataContainerId, 
                   filtered.DataInstanceId                    
            from dataValue dv
            join 
            (
                select dc.ModelEntityId as 'ContainerModelEntityId', 
                       di.DataInstanceId, 
                       di.DataContainerId,
                       dc.ParentDataContainerId 
                from datainstance di
                    join datavalue dv on di.Datainstanceid = dv.datainstanceid
                    join datacontainer dc on dc.DataContainerId = di.datacontainerId
                    join #filters f on dv.ModelEntityId = f.ModelEntityId and f.ValueText = dv.ValueText
                where ISNULL(dc.ParentDataContainerId,0) = ISNULL(null,0) and di.IsCurrent = 1 and di.ModelEntityId = @ContainerModelEntityId
                group by dc.ModelEntityId, dc.ParentDataContainerId, di.DataInstanceId, di.DataContainerId
                having (count(di.DataInstanceId) = (select count(ModelEntityId) from #Filters) ) 
            )
            filtered on filtered.dataInstanceId = dv.dataInstanceId
            where dv.ModelEntityId = @SortFieldId
        ) tbl
        WHERE row >= @LowerBound AND 
              row < @UpperBound 
END
ELSE
BEGIN
    INSERT INTO #SelectedRecords
    SELECT Row, ContainerModelEntityId, DataContainerId, DataInstanceId, ParentDataContainerId 
    FROM
    ( 
        select ROW_NUMBER() OVER (ORDER BY dv.ValueText) AS row,
               di.ModelEntityId as 'ContainerModelEntityId', 
               dc.DataContainerId, 
               di.DataInstanceId, 
               dv.ModelEntityId, 
               dc.ParentDataContainerId          
        from datacontainer dc
            inner join dataInstance di on dc.DataContainerId = di.DataContainerId
            left outer join dataValue dv on di.DataInstanceId = dv.DataInstanceId and dv.ModelEntityId=@SortFieldId
        where (@ParentRecordId is NULL or ISNULL(dc.ParentDataContainerId,0) = ISNULL(@ParentRecordId,0)) and 
               di.IsCurrent = 1 and di.ModelEntityId=@ContainerModelEntityId
    ) tbl
    WHERE tbl.row >= @LowerBound AND
          tbl.row < @UpperBound
END 


DECLARE @Count int
SELECT @Count = (SELECT COUNT(*) FROM DataContainer dc
INNER JOIN DataInstance di ON di.DataContainerId = dc.DataContainerId
WHERE di.ModelEntityId=@ContainerModelEntityId AND ISNULL(dc.ParentDataContainerId,0) = ISNULL(@ParentRecordId,0) AND di.IsCurrent=1)

    SELECT ContainerModelEntityId, DataContainerId, ParentDataContainerId, isnull(dv.ModelEntityId, @sortFieldId) as 'ModelEntityId', dv.ValueText, 
        @Count [TotalRecords] FROM
    #SelectedRecords sr  
    left outer join dataValue dv ON sr.DataInstanceId = dv.DataInstanceId
    ORDER BY
    CASE
        WHEN @Ascending = 1 THEN (RANK() OVER (ORDER BY sr.row ASC))
        WHEN @Ascending = 0 THEN (RANK() OVER (ORDER BY sr.row DESC))
    END

END

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜