如何将动态创建的过滤器作为存储过程的参数传递给 SQL 服务器和过滤器数据?

How to pass dynamically created filters as parameter of stored procedure in SQL Server and filter data?

我如何传递一些 动态过滤器(从 table tblMarketingCampaignFilters 在 SQL 服务器中填充)并将它们与 TargetColumntblMarketingUsers 中?

澄清一下,我有所有代码来生成和填充过滤器并分配 InputTypes(它可以是数字、日期、字符串或带有复选框的布尔值),但是 page 应该添加用户想要的(n 过滤器)。

这是一张图片,显示了我的 table 是如何定义的

我必须将过滤器tblMarketingUsers中的(待添加)进行比较。

示例:

这是我在 页面

中的表单筛选部分

现在我只有4个过滤器,可能是10个,我不知道。

谢谢。

PS:我认为我在 tblMarketingCampaignFilters 中缺少一个 TableTarget,如果系统必须查看另一个 table,而不仅仅是 tblMarketingUsers,不过没关系。

PS2:我正在考虑将过滤器作为文本传递,使用逗号分隔的样式,然后将其插入 transMarketingCampaignFilters,但仍然不知道如何 动态比较他们,我老板说"use cursors in SQL"

编辑

感谢您的回复和评论。

这是我想做的一种方法。我需要在 tblMarketingCampaignFilters 中添加 Operator 列(它将存储类似: '=' , '<', '>', 'LIKE') ,顺便说一句,这个存储过程将假设带有过滤器的活动已经在表单上提交,并且所有数据都存储在 transMarketingCampaignFilters

    CREATE PROCEDURE usp_MarketingUsersGetFiltered
    -- Add the parameters for the stored procedure here
    @CampaignId int,
    @Debug BIT = 0
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;
    declare @sql varchar(max) = '', @Nsql nvarchar(max), @DatabaseId INT;
    -- Insert statements for procedure here

set @DatabaseId = (SELECT DatabaseId from tblMarketingCampaigns where Id=@CampaignId); select @sql += ' AND '+quotename(f.TargetColumn) + f.Operator + case f.InputType when 'int' then cast(cf.Value as int) else quotename(cf.Value,'''') end from dbo.transMarketingCampaignFilters as cf join dbo.tblMarketingCampaignFilters as f on cf.CampaignFilterId = f.Id where cf.CampaignId = @CampaignId set @sql = ' select MarketingUserId, FirstName, LastName, Email, CompanyId from dbo.tblMarketingUsers where DatabaseId = @DatabaseId '+ @sql+' OPTION (RECOMPILE)'; if @Debug = 1 print @sql; set @sql = @Nsql; exec sys.sp_executesql @Nsql,N'@DatabaseId INT',@DatabaseId; END GO

1) 将过滤器数据作为用户定义类型或作为 XML 参数传递到存储过程中。

2) 检查存储过程中灵活参数集的内容,对于最常见的用例,调用具有满足最常见情况的固定 SQL 内容的子存储过程。这使得这些程序可以针对其目的进行优化。

3) 在过滤器集不匹配任何高频预测模式的情况下,使用动态生成的 SQL 存储过程层内的 where-clause 来生成匹配项。

在所有情况下,在业务逻辑层生成参数化 SQL 并针对 SQL 服务器执行它很诱人,如果您无法识别任何非常频繁的使用,这可能是您的最佳方法-cases,但它缺乏(2)中描述的分支的测试能力和东部性能优化。

在存储过程中添加所有可能的过滤器作为搜索参数。如果设置了过滤器,则参数不为空,否则为空。然后,在 where 子句中,只有参数不为 null 时才使用该参数。像这样:

WHERE (@LastLoginDate IS NULL OR t.LoginDate<@LastLoginDate) AND
      (@CityId IS NULL OR t.CityId=@CityId) 

最后,我写了 Javascript 代码(有点复杂)到 :

  • 创建动态过滤器及其各自的输入
    1. 我的实际类型只有 4 (int,bit,varchar,date)
    2. 对于 'int' 动态创建一个 <input type="number">
    3. 对于 'date' 动态创建一个 <input type="text"> ,带有日期插件
    4. 等等...
  • 我创建了一个数组来存储我的过滤器的 ID,并通过 AJAX 调用(和完整的表格)发送到服务器

然后在服务器代码中 (C#) 我已经将代码写入:

  • 保存活动详细信息。
  • 遍历参数数组。
    1. 用AddCampaign存储过程提供的CampaignId保存每个过滤器(保存活动后),每个select表单值提供的过滤器ID ,以及在生成的输入中提供的值。

然后在 SQL 服务器 中,我刚刚使用了我在问题上提供的存储过程,稍作修改:

CREATE PROCEDURE usp_MarketingUsersGetFiltered
-- Add the parameters for the stored procedure here
@CampaignId int,
@Debug BIT = 0
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
declare @sql varchar(max) = '', @Nsql nvarchar(max), @DatabaseId INT;
-- Insert statements for procedure here

set @DatabaseId = (SELECT DatabaseId from tblMarketingCampaigns where Id=@CampaignId);
select @sql +=  ' AND '+quotename(f.TargetColumn) + f.Operation + 
            case f.InputType 
            when 'int' then cf.Value
            when 'bit' then cf.Value
            else quotename(cf.Value,'''')               
            end
from dbo.transMarketingCampaignFilters as cf
join dbo.tblMarketingCampaignFilters as f
on cf.CampaignFilterId = f.Id
where cf.CampaignId = @CampaignId

 set @sql = '
 select MarketingUserId,
        FirstName,
        LastName,
        tblMarketingUsers.Email as UserEmail,
        CompanyId,
        CompanyName,
        Address1,
        Address2,
        City,
        SmartInsightProfile,
        LastLoginDate,
        AdvancedProfileStatus
 from dbo.tblMarketingUsers 
 left join dbo.tblCompanies on tblMarketingUsers.CompanyId=tblCompanies.Id
 where DatabaseId = @DatabaseId
 '+ @sql+'
 OPTION (RECOMPILE)';

if @Debug = 1 print @sql;
set @Nsql = @sql;
exec sys.sp_executesql @Nsql,N'@DatabaseId INT',@DatabaseId;

END
GO

我的桌子是这样的

tblMarketingCampaignFilters 存储的行类似于:

(Id , Name , InputType ,TargetColumn ,Operator)

(1, 'Advanced Profile Status', 'int', 'AdvancedProfileStatus', '<')

(2, 'Last Login Date', 'date', 'LastLoginDate', '<')

(3, 'Geo Location (City)', 'varchar', 'City', 'LIKE')

最终结果:

 select MarketingUserId,
        FirstName,
        LastName,
        tblMarketingUsers.Email as UserEmail,
        CompanyId,
        CompanyName,
        Address1,
        Address2,
        City,
        SmartInsightProfile,
        LastLoginDate,
        AdvancedProfileStatus
 from dbo.tblMarketingUsers 
 left join dbo.tblCompanies on tblMarketingUsers.CompanyId=tblCompanies.Id
 where DatabaseId = 3
  AND [City]LIKE'%salta%' AND [SmartInsightProfile]!=1 AND [LastLoginDate]<'20150708' AND [AdvancedProfileStatus]<42
 OPTION (RECOMPILE)

非常感谢您的帮助!

我知道这不是最好的方法,但现在对我有用!

希望这对其他人有所帮助。