Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server SQL Server在where子句中包含搜索筛选器列_Sql Server_Tsql_Stored Procedures - Fatal编程技术网

Sql server SQL Server在where子句中包含搜索筛选器列

Sql server SQL Server在where子句中包含搜索筛选器列,sql-server,tsql,stored-procedures,Sql Server,Tsql,Stored Procedures,我有一个SQL Server数据库,其中有一个包含客户数据的Person表。在我的web应用程序中,弹出式搜索框jqGrid允许用户指定搜索中使用的字段/过滤器以及操作和数据。因此,字段类似于名称、上次访问日期等。这些字段映射到Person表,尽管并非所有字段都与列名匹配,并且操作都包含、以开头、以结尾、大于等。每个字段都作为两个字母的代码传入,如“cn”、“bw”、“ew”、“gt”。总共有15个不同的字段可以进行筛选,12个操作 表中大约有50列,所以我在这里只列出了一些: CREATE T

我有一个SQL Server数据库,其中有一个包含客户数据的Person表。在我的web应用程序中,弹出式搜索框jqGrid允许用户指定搜索中使用的字段/过滤器以及操作和数据。因此,字段类似于名称、上次访问日期等。这些字段映射到Person表,尽管并非所有字段都与列名匹配,并且操作都包含、以开头、以结尾、大于等。每个字段都作为两个字母的代码传入,如“cn”、“bw”、“ew”、“gt”。总共有15个不同的字段可以进行筛选,12个操作

表中大约有50列,所以我在这里只列出了一些:

CREATE TABLE [dbo].[Person]
(
    [PersonId] [int] IDENTITY(1,1) NOT NULL,
    [PersonTypeId] [int] NULL,
    [Firstname] [nvarchar](200) NULL,
    [Middlename] [nvarchar](200) NULL,
    [Lastname] [nvarchar](200) NULL,
    [Name] [nvarchar](200) NULL,
)

INSERT INTO [dbo].[Person]([PersonTypeId],[Firstname],[Middlename],[Lastname],[Name]) 
VALUES (1, 'James', 'Joseph', 'Martin', ''),
       (1, 'Jim', 'Joseph', 'Martyn', ''),
       (1, 'James', 'John', 'Martine', ''),
       (2, 'James', 'Sean', 'Martin', 'Martin & Co'),
       (2, 'John', 'Joseph', 'Martin', 'Martin & Martin')
我向存储过程中添加了一个表值参数,以传递搜索条件,该条件工作良好,因此现在在搜索存储过程中,我有一个udt,其中包含用户输入的所有字段/操作/数据

CREATE TYPE [dbo].[udt_Filter] AS TABLE
        (
            [Field] [nvarchar](50),
            [Op] [nvarchar](50),
            [Data] [nvarchar](50)
        )
通过udt传入的过滤器如下所示:

Field   Op  Data
'Name', 'bw', 'Mart'
'LastVisit', 'gt', '01.07.2017'
现在我想知道在搜索中包含过滤器的最佳方式是什么。我知道我可以使用动态SQL使其工作,但如果可能的话,我更喜欢使用联接,但是我看不到任何将字段名筛选器与Person表中的数据联接的方法

ALTER PROCEDURE [dbo].[pr_GetPersons]
    (
        @Filters dbo.udt_Filter READONLY,
        @Operation nvarchar(3) -- AND or OR
    )
AS
BEGIN
    SELECT [PersonTypeId], [Firstname], [Middlename], [Lastname], [Name] 
    FROM [dbo].[Person]
    WHERE PersonTypeId IN (1, 2, 3)
        -- @Operation can I somehow join to @Filters and filter the Select result using each row in @Filters??
END

所有过滤条件都与AND或or组合,AND或or作为@操作传递给存储过程

不可能通过Person表和@Filters表参数之间的联接来解决此动态筛选问题。如果没有动态SQL,使用15个字段和12个运算符,那么最终将得到一个怪物where子句。我怀疑存储过程在这种情况下是否能正常运行

相反,我建议使用动态SQL。以下是一个可以用作起点的存储过程:

CREATE PROCEDURE [dbo].[pr_GetPersons]
    (@Filters dbo.udt_Filter READONLY)
AS
BEGIN

    DECLARE
        @SelectList nvarchar(max),
        @WhereClause nvarchar(max),
        @SqlCommand nvarchar(max)

    SET @SelectList = ISNULL(STUFF((SELECT ', ' + QUOTENAME(Field) AS [text()] FROM @Filters FOR XML PATH('')), 1, 1, ''), '*')

    SET @WhereClause = STUFF((
        SELECT 
            ' AND ' +
            -- Translate opcodes into SQL Server expressions.
            CASE Op
                WHEN 'cn' THEN QUOTENAME(Field) + ' LIKE ' + QUOTENAME('%' + Data + '%', '''')
                WHEN 'bw' THEN QUOTENAME(Field) + ' LIKE ' + QUOTENAME(Data + '%', '''')
                WHEN 'ew' THEN QUOTENAME(Field) + ' LIKE ' + QUOTENAME('%' + Data, '''')
                WHEN 'gt' THEN QUOTENAME(Field) + '>' + QUOTENAME(Data, '''')
                WHEN 'lt' THEN QUOTENAME(Field) + '<' + QUOTENAME(Data, '''')
            END AS [text()] 
        FROM 
            @Filters
        FOR XML PATH(''), type).value('.', 'nvarchar(max)'), 
        1, 5, '')

    SET @SqlCommand = 'SELECT ' + @SelectList + ' FROM dbo.Person WHERE PersonTypeId IN (1, 2, 3)' + ISNULL(NULLIF(' AND ', @WhereClause) + @WhereClause, '')

    EXEC(@SqlCommand)

END
它只返回筛选器中的列。如果希望它返回表中的所有列,而不管过滤器中有什么,请将@SelectList变量设置为*

所有筛选准则都与AND运算符联接。在@Fields变量中,没有指示如何组合它们。所以我想和运算符就是所需要的

解释@Filters表中的操作代码以生成where子句的CASE表达式可以移动到它自己的函数中。QUOTENAMEData,用于在数据为字符串且包含单引号的情况下形成正确的字符串

该过程不会检查Person表中是否存在筛选器字段。应特别注意筛选值数据,尤其是日期/时间和十进制类型,因为在形成where子句或检查筛选值类型是否与Person表中的列类型匹配时,没有类型转换,所有筛选值都用作字符串

ALTER PROCEDURE [dbo].[pr_GetPersons]
    (
        @Filters dbo.udt_Filter READONLY,
        @Operation nvarchar(3) -- AND or OR
    )
AS
BEGIN
    SELECT [PersonTypeId], [Firstname], [Middlename], [Lastname], [Name] 
    FROM [dbo].[Person]
    WHERE PersonTypeId IN (1, 2, 3)
        -- @Operation can I somehow join to @Filters and filter the Select result using each row in @Filters??
END

希望有帮助。

不可能通过Person表和@Filters表参数之间的联接来解决此动态筛选问题。如果没有动态SQL,使用15个字段和12个运算符,那么最终将得到一个怪物where子句。我怀疑存储过程在这种情况下是否能正常运行

相反,我建议使用动态SQL。以下是一个可以用作起点的存储过程:

CREATE PROCEDURE [dbo].[pr_GetPersons]
    (@Filters dbo.udt_Filter READONLY)
AS
BEGIN

    DECLARE
        @SelectList nvarchar(max),
        @WhereClause nvarchar(max),
        @SqlCommand nvarchar(max)

    SET @SelectList = ISNULL(STUFF((SELECT ', ' + QUOTENAME(Field) AS [text()] FROM @Filters FOR XML PATH('')), 1, 1, ''), '*')

    SET @WhereClause = STUFF((
        SELECT 
            ' AND ' +
            -- Translate opcodes into SQL Server expressions.
            CASE Op
                WHEN 'cn' THEN QUOTENAME(Field) + ' LIKE ' + QUOTENAME('%' + Data + '%', '''')
                WHEN 'bw' THEN QUOTENAME(Field) + ' LIKE ' + QUOTENAME(Data + '%', '''')
                WHEN 'ew' THEN QUOTENAME(Field) + ' LIKE ' + QUOTENAME('%' + Data, '''')
                WHEN 'gt' THEN QUOTENAME(Field) + '>' + QUOTENAME(Data, '''')
                WHEN 'lt' THEN QUOTENAME(Field) + '<' + QUOTENAME(Data, '''')
            END AS [text()] 
        FROM 
            @Filters
        FOR XML PATH(''), type).value('.', 'nvarchar(max)'), 
        1, 5, '')

    SET @SqlCommand = 'SELECT ' + @SelectList + ' FROM dbo.Person WHERE PersonTypeId IN (1, 2, 3)' + ISNULL(NULLIF(' AND ', @WhereClause) + @WhereClause, '')

    EXEC(@SqlCommand)

END
它只返回筛选器中的列。如果希望它返回表中的所有列,而不管过滤器中有什么,请将@SelectList变量设置为*

所有筛选准则都与AND运算符联接。在@Fields变量中,没有指示如何组合它们。所以我想和运算符就是所需要的

解释@Filters表中的操作代码以生成where子句的CASE表达式可以移动到它自己的函数中。QUOTENAMEData,用于在数据为字符串且包含单引号的情况下形成正确的字符串

该过程不会检查Person表中是否存在筛选器字段。应特别注意筛选值数据,尤其是日期/时间和十进制类型,因为在形成where子句或检查筛选值类型是否与Person表中的列类型匹配时,没有类型转换,所有筛选值都用作字符串

ALTER PROCEDURE [dbo].[pr_GetPersons]
    (
        @Filters dbo.udt_Filter READONLY,
        @Operation nvarchar(3) -- AND or OR
    )
AS
BEGIN
    SELECT [PersonTypeId], [Firstname], [Middlename], [Lastname], [Name] 
    FROM [dbo].[Person]
    WHERE PersonTypeId IN (1, 2, 3)
        -- @Operation can I somehow join to @Filters and filter the Select result using each row in @Filters??
END

希望有帮助。

过滤器总是与and、or或用户指定的选项结合使用吗?一些建议的背景阅读是。嗨@HABO-我没有提到所有的语句都与“或”和“或”结合,与第一句WHERE PersonTypeId结合在一起。你如何处理子表达式,例如A和B或C,notD或e,而不是F?不清楚如何在字段/Op/Data中表示,更不用说和/或了。@HABO没有任何子查询-所有筛选条件都将与and或or组合。这是使用操作参数确定的,因此Op可以大于或包含?对于年龄>=65且姓氏如“%adelia”或ShoeSize包含“EEE”,筛选表将包含什么内容?如果需要,请随意选择。过滤器是否总是与and、or或用户指定的选项结合使用?一些建议
ted背景阅读是。Hi@HABO-我没有提到所有的语句都与AND或or结合,与第一句WHERE PersonTypeId结合在一起。你如何处理子表达式,例如A和B或C和notD或e而不是F?不清楚如何在字段/Op/Data中表示,更不用说和/或了。@HABO没有任何子查询-所有筛选条件都将与and或or组合。这是使用操作参数确定的,因此Op可以大于或包含?对于年龄>=65且姓氏如“%adelia”或ShoeSize包含“EEE”,筛选表将包含什么内容?如果需要,请随时联系。