如何将动态创建的过滤器作为存储过程的参数传递给 SQL 服务器和过滤器数据?
How to pass dynamically created filters as parameter of stored procedure in SQL Server and filter data?
我如何传递一些 动态过滤器(从 table tblMarketingCampaignFilters
在 SQL 服务器中填充)并将它们与 TargetColumn
在 tblMarketingUsers
中?
澄清一下,我有所有代码来生成和填充过滤器并分配 InputTypes
(它可以是数字、日期、字符串或带有复选框的布尔值),但是 page 应该添加用户想要的(n 过滤器)。
这是一张图片,显示了我的 table 是如何定义的
我必须将过滤器与tblMarketingUsers
中的列(待添加)进行比较。
示例:
- LastLoginDate > '20150701' 如果是日期,
- 高级配置文件状态 > 50(百分比)如果是数字,
- InBothSystems = 0 如果是勾选的复选框
这是我在 页面
中的表单筛选部分
现在我只有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 代码(有点复杂)到 :
- 创建动态过滤器及其各自的输入
- 我的实际类型只有 4 (int,bit,varchar,date)
- 对于 'int' 动态创建一个
<input type="number">
- 对于 'date' 动态创建一个
<input type="text">
,带有日期插件
- 等等...
- 我创建了一个数组来存储我的过滤器的 ID,并通过 AJAX 调用(和完整的表格)发送到服务器
然后在服务器代码中 (C#) 我已经将代码写入:
- 保存活动详细信息。
- 遍历参数数组。
- 用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)
非常感谢您的帮助!
我知道这不是最好的方法,但现在对我有用!
希望这对其他人有所帮助。
我如何传递一些 动态过滤器(从 table tblMarketingCampaignFilters
在 SQL 服务器中填充)并将它们与 TargetColumn
在 tblMarketingUsers
中?
澄清一下,我有所有代码来生成和填充过滤器并分配 InputTypes
(它可以是数字、日期、字符串或带有复选框的布尔值),但是 page 应该添加用户想要的(n 过滤器)。
这是一张图片,显示了我的 table 是如何定义的
我必须将过滤器与tblMarketingUsers
中的列(待添加)进行比较。
示例:
- LastLoginDate > '20150701' 如果是日期,
- 高级配置文件状态 > 50(百分比)如果是数字,
- InBothSystems = 0 如果是勾选的复选框
这是我在 页面
中的表单筛选部分现在我只有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 代码(有点复杂)到 :
- 创建动态过滤器及其各自的输入
- 我的实际类型只有 4 (int,bit,varchar,date)
- 对于 'int' 动态创建一个
<input type="number">
- 对于 'date' 动态创建一个
<input type="text">
,带有日期插件 - 等等...
- 我创建了一个数组来存储我的过滤器的 ID,并通过 AJAX 调用(和完整的表格)发送到服务器
然后在服务器代码中 (C#) 我已经将代码写入:
- 保存活动详细信息。
- 遍历参数数组。
- 用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)
非常感谢您的帮助!
我知道这不是最好的方法,但现在对我有用!
希望这对其他人有所帮助。