CREATE TYPE [dbo].[Param] AS TABLE ( [FlagVal] NVARCHAR(100) )
GO
DECLARE @Param [dbo].[Param];
INSERT INTO @Param ( [FlagVal] )
VALUES ( 'Yes' )
, ( 'NO' )
, ( 'Maybe_JKL' )
, ( 'Maybe_XYZ' )
--, ( 'Maybe_PQR' )
;
DECLARE @Sql NVARCHAR(MAX);
SET @Sql = N'
DECLARE @DataT TABLE ( [ID] INT IDENTITY(1,1), [Flag] INT, [FValY] NVARCHAR(45), [FValN] NVARCHAR(45), [FValMB] NVARCHAR(45) );
INSERT INTO @DataT ( [Flag], [FValY], [FValN], [FValMB] )
VALUES ( 10, ''XYZ'', NULL, NULL )
, ( 10, ''ABC'', NULL, NULL )
, ( 10, ''XYZ'', NULL, NULL )
, ( 100, NULL, ''MNO'', NULL )
, ( 100, NULL, ''STU'', NULL )
, ( 1000, NULL, NULL, ''Maybe_JKL'' )
, ( 1000, NULL, NULL, ''Maybe_XYZ'' )
, ( 1000, NULL, NULL, ''Maybe_PQR'' )
, ( NULL, NULL, NULL, NULL )
, ( NULL, NULL, NULL, NULL );
SELECT [ID]
, [Flag]
, [FValY]
, [FValN]
, [FValMB]
FROM @DataT DT
WHERE [ID] < 1000'
IF EXISTS (SELECT TOP (1) 1 FROM @Param) -- Code within this clause needs improvement
BEGIN
SET @Sql = CONCAT(@Sql,N' AND (');
IF EXISTS (SELECT TOP (1) 1 FROM @Param WHERE [FlagVal] = 'Yes')
BEGIN
SET @Sql = CONCAT(@Sql,N' [Flag] = 10');
END
ELSE
BEGIN
SET @Sql = CONCAT(@Sql,N' [Flag] != 10');
END
IF EXISTS (SELECT TOP (1) 1 FROM @Param WHERE [FlagVal] = 'NO')
BEGIN
SET @Sql = CONCAT(@Sql,N' OR [Flag] = 100');
END
ELSE
BEGIN
SET @Sql = CONCAT(@Sql,N' AND [Flag] != 100');
END
IF EXISTS (SELECT TOP (1) 1 FROM @Param WHERE [FlagVal] NOT IN ('Yes','No'))
BEGIN
SET @Sql = CONCAT(@Sql,N' OR ([Flag] = 1000
AND EXISTS (SELECT TOP (1) 1
FROM @Param P
WHERE DT.[FValMB] = P.[FlagVal]))');
END
ELSE
BEGIN
SET @Sql = CONCAT(@Sql,N' AND ([Flag] != 1000
AND NOT EXISTS (SELECT TOP (1) 1
FROM @Param P
WHERE DT.[FValMB] = P.[FlagVal]))');
END
SET @Sql = CONCAT(@Sql,N' )');
END
PRINT @Sql
EXEC sp_executesql
@Sql,
N'@Param [dbo].[Param] READONLY',
@Param = @Param
DROP TYPE [dbo].[Param]
GO
目标:
高级别:根据@DataT
中选择的内容过滤@Param
数据。如果@Param
为空,请勿过滤数据。
低级别:
@Param
:这是一个过滤器参数,填充后会有“是”,“否”或特定的“Maybe_xxx”值。这用于过滤@DataT
表中可用的数据。
@DataT
:这是实际的数据表。它有Id
列(标识),Flag
列(是(10),否(100)和可能(1000)),每个标志类型有一列({{1}填充“是/ 10”标记,[FValY]
填充“No / 100”标记,[FValN]
填充“Maybe / 1000”标记
[FValMB]
过滤器如何工作?此过滤器可以为空或填充“是”和/或“否”和/或特定@Param
列的值。它可以是Yes / No / [FValMB] -value的任意组合。
如果[FValMB]
仅填充“是”,则只返回前三个记录。
如果@Param
仅填充“否”,则只返回第4和第5条记录。
如果@Param
仅填充了“Maybe”(@Param
值),那么只应返回“Maybe”标记的记录[FValMB]
。
如果填充“是”和“否”,则只返回前五个记录。
如果填写“是”和“可能”,则只返回前三个以及第6到第8条记录中的任何匹配项......等等
如果@Param value(s) = [FValMB]
为空,则不应对此进行过滤。
我的尝试:
我在算术部分遇到问题,我需要检查一个/多个组合等。我需要帮助改进最外层IF语句中的代码。
答案 0 :(得分:2)
没有足够的积分来为更多问题添加评论。 如果可能的话,通过执行类似的操作来简化代码,因为您似乎知道每个项目的价值。
CREATE TYPE [dbo].[Param] AS TABLE ( [FlagVal] NVARCHAR(100),NumValue int )
)
GO
DECLARE @Param [dbo].[Param];
INSERT INTO @Param ( [FlagVal] )
VALUES ( 'Yes',10 )
, ( 'NO',100 )
, ( 'Maybe_JKL',### )
, ( 'Maybe_XYZ',### )
--, ( 'Maybe_PQR' )
;
添加数值将简化代码。也许你可以从中构建where子句。甚至可以添加missing_Y_and_N并插入值。
答案 1 :(得分:1)
有时你修改表/函数的方式不会影响代码的任何部分。你可以在这里做类似的事情。
甚至替代解决方案也会整洁干净。如果您有大量的记录并且您的真实场景与上面描述的不同,那么您可以考虑动态搜索,但您编写的那个并不符合标记。
drop type [dbo].[Param]
CREATE TYPE [dbo].[Param] AS TABLE ( [FlagVal] NVARCHAR(100),FlagID as
case when FlagVal='Yes' then 10 when FlagVal='No' then 100
when FlagVal like '%Maybe%' then 1000 else null end)
GO
DECLARE @Param [dbo].[Param];
INSERT INTO @Param ( [FlagVal] )
VALUES ( 'Yes' )
, ( 'NO' )
, ( 'Maybe_JKL' )
, ( 'Maybe_XYZ' )
, ( 'Maybe_PQR' )
;
DECLARE @DataT TABLE ( [ID] INT IDENTITY(1,1), [Flag] INT, [FValY] NVARCHAR(45),
[FValN] NVARCHAR(45), [FValMB] NVARCHAR(45) );
INSERT INTO @DataT ( [Flag], [FValY], [FValN], [FValMB] )
VALUES ( 10, 'XYZ', NULL, NULL )
, ( 10, 'ABC', NULL, NULL )
, ( 10, 'XYZ', NULL, NULL )
, ( 100, NULL, 'MNO', NULL )
, ( 100, NULL, 'STU', NULL )
, ( 1000, NULL, NULL, 'Maybe_JKL' )
, ( 1000, NULL, NULL, 'Maybe_XYZ' )
, ( 1000, NULL, NULL, 'Maybe_PQR' )
, ( NULL, NULL, NULL, NULL )
, ( NULL, NULL, NULL, NULL );
SELECT * from @DataT
select * from @Param
select * from @DataT dt
where exists(select [FlagVal] from @Param p
where p.FlagID=dt.[Flag] and(( p.FlagVal=dt.FValMB) or (dt.FValMB is null)))
------Alternatively declare table variable and use it instead of table type
DECLARE @TableTypeAlt TABLE ( [FlagVal] NVARCHAR(100),FlagID int)
insert into @TableTypeAlt
select FlagVal,
case when FlagVal='Yes' then 10
when FlagVal='No' then 100 when FlagVal like '%Maybe%' then 1000 else null end
from @Param
select * from @TableTypeAlt
- 或者第三种解决方案,如果你根本不能改变类型 试试这个,
select * from @DataT dt
where exists(
select [FlagVal] from @Param p
where case when FlagVal='Yes' then 10 when FlagVal='No' then 100
when FlagVal like '%Maybe%' then 1000 else null end=dt.[Flag] and(( p.FlagVal=dt.FValMB) or (dt.FValMB is null))
)
答案 2 :(得分:1)
不要为此使用动态SQL,正常声明@DataT表并继续
从@DataT创建一个#temp表(实际数据表)以根据列创建行
if object_id('tempdb..#temp') is not null drop table #temp
select distinct [Flag],case when isnull(FValY,'') <> '' then 'Yes'
when isnull(fvaln,'')<>'' then 'NO'
when isnull(fvalmb,'') <> '' then 'Maybe_' end As FlagVal into #temp
from @DataT where isnull(Flag,'') <>''
使用@param和@DataT
加入#temp表select distinct c.* from @Param a inner join #temp b
on a.[FlagVal] like b.FlagVal + '%'
inner join @DataT c on b.Flag = c.Flag
您将获得所需的输出
答案 3 :(得分:0)
我为这个例子制作了永久性的桌子,因为它更简单,更容易将这一部分考虑在内。不应该在候选解决方案的内容上有所作为。像另一张海报一样,有几个要求问题我自己无法回答,但没有要点的问题。具体来说,我注意到您的示例数据没有包含两个或更多FVal *列值的行。因此,我没有测试/适应那个(还)。
/* BEGIN One-time structure setup */
CREATE TYPE [dbo].[Param] AS TABLE ( [FlagVal] NVARCHAR(100) )
GO
CREATE TABLE [dbo].[DataT](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Flag] [int] NULL,
[FValY] [nvarchar](45) NULL,
[FValN] [nvarchar](45) NULL,
[FValMB] [nvarchar](45) NULL,
CONSTRAINT [PK_DataT] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
/* END One-time structure setup */
/* BEGIN test data setup */
INSERT INTO DataT ( [Flag], [FValY], [FValN], [FValMB] )
VALUES ( 10, 'XYZ', NULL, NULL )
, ( 10, 'ABC', NULL, NULL )
, ( 10, 'XYZ', NULL, NULL )
, ( 100, NULL, 'MNO', NULL )
, ( 100, NULL, 'STU', NULL )
, ( 1000, NULL, NULL, 'Maybe_JKL' )
, ( 1000, NULL, NULL, 'Maybe_XYZ' )
, ( 1000, NULL, NULL, 'Maybe_PQR' )
, ( NULL, NULL, NULL, NULL )
, ( NULL, NULL, NULL, NULL )
;
/* END test data setup */
/* BEGIN test param */
DECLARE @Param Param;
INSERT INTO @Param ( [FlagVal] )
VALUES ( 'Yes' )
,( 'NO' )
, ( 'Maybe_JKL' )
, ( 'Maybe_XYZ' )
, ( 'Maybe_PQR' )
;
/* END test param */
/* BEGIN query */
DECLARE @ParamHasYes bit;
SET @ParamHasYes = 0;
DECLARE @ParamHasNo bit;
SET @ParamHasNo = 0;
IF EXISTS (SELECT FlagVal FROM @Param WHERE LOWER(FlagVal) = 'yes') SET @ParamHasYes = 1;
IF EXISTS (SELECT FlagVal FROM @Param WHERE LOWER(FlagVal) = 'no') SET @ParamHasNo = 1;
WITH DataView AS
(
SELECT
Flag
,FValY
,FValN
,FValMB
/* IMPORTANT - non-matches for Y and N columns below must be set to NULL (NOT 0!)
so that rows are excluded when the param list is empty
i.e., @ParamHasYes = 0 and/or @ParamHasNo = 0 */
,CASE WHEN FValY IS NOT NULL THEN 1 ELSE NULL END AS RowHasYes
,CASE WHEN FValN IS NOT NULL THEN 1 ELSE NULL END AS RowHasNo
FROM
DataT
)
-- Get all the rows that have a value for the yes column
SELECT
DataView.*
FROM
DataView
WHERE
RowHasNo = @ParamHasNo
UNION ALL
-- Get all the rows that have a value for the no column
SELECT
DataView.*
FROM
DataView
WHERE
RowHasYes = @ParamHasYes
UNION ALL
-- Get all the rows that match the MB list
SELECT
DataView.*
FROM
DataView
INNER JOIN @Param P ON DataView.FValMB = P.FlagVal
ORDER BY
Flag
,FValY
,FValN
,FValMB
;
/* END query */