使用CTE和变量输入优化SQL查询

时间:2019-05-27 16:40:16

标签: java sql sql-server database

我正在尝试使用Java运行以下SQL脚本,并且从JDBCTemplate获得没有结果集的问题。我考虑过使用函数/存储过程来减少它,并希望获得一些帮助:

SQL:
第一部分:

SET NOCOUNT ON
IF OBJECT_ID('tempdb.dbo.#tempSearch', 'U') IS NOT NULL
DROP TABLE #tempSearch;

CREATE TABLE #tempSearch
(
    ID int,
    Value VARCHAR(255)
)
INSERT INTO #tempSearch
VALUES(1,'Variable1'),
(2,'Variabl2');  

第二部分:

with cte as (
    select RoleID,','+replace(replace(GroupNames,',',',,'),' ','')+',' GroupNames from UserGroup_Role_Mapping
    )
    ,cte2 as(
    select cte.RoleID, replace(cte.GroupNames,','+Value+',','') as GroupNames, s.ID, s.Value 
    from cte
    join #tempSearch s on ID=1
    union all
    select cte2.RoleID, replace(cte2.GroupNames,','+s.Value+',','') as l, s.ID ,s.Value
    from cte2
    join #tempSearch s on s.ID=cte2.ID+1
)


SELECT a.Role, a.Sort_Order, a.Parent, a.Parent_ID, a.Parent_URL, a.Child, a.Child_ID,a.Child_URL
FROM Config_View a
WHERE a.Role IN (
    Select Name from (
        Select distinct RoleID from cte2 where len(GroupNames)=0
    ) tempRoles
    join User_Role
    on tempRoles.RoleID = User_Role.ID
    ) 

DROP TABLE #tempSearch

我当时认为第一部分可以在存储过程中完成。我确实在这里(stored procedure with variable number of parameters读过关于用变量列表制作表格的信息,但不确定如何像我从上面那样(1,Variable1等)那样在循环中设置这些变量。

我认为第二部分可以单独存在吗?

所以我更新的查询可能是: 1.调用storeprocedure(variable1 ... variablex); 2. SQL第2部分?

如果有人可以帮助,那就太好了!

1 个答案:

答案 0 :(得分:1)

可以在两个单独的批次中执行此操作,但是前提是您可以确保第一个批次在会话范围内运行,而不在嵌套的批次中运行(例如,通过sp_executesql)。在嵌套批处理中创建的临时表(如存储过程或预准备语句)会在嵌套批处理结束时自动销毁。因此,这取决于您如何称呼它。我的猜测是,PreparedStatement无法正常工作。

执行此操作的正确方法可能是使用具有表值参数或JSON(对于SQL 2016+)或XML参数的存储过程,然后在存储过程主体中对其进行解析。参见https://docs.microsoft.com/en-us/sql/connect/jdbc/using-table-valued-parameters?view=sql-server-2017

您还可以使用TSQL批处理而不是存储过程并绑定表值参数或包含JSON的NVarchar(max)参数。

使用TVP,您可以简单地使用以下批处理:

with s as (
     select * from ? --bind a table-valued parameter here
     ), cte as (
    select RoleID,','+replace(replace(GroupNames,',',',,'),' ','')+',' GroupNames from UserGroup_Role_Mapping
    )
    ,cte2 as(
    select cte.RoleID, replace(cte.GroupNames,','+Value+',','') as GroupNames, s.ID, s.Value 
    from cte
    join s on ID=1
    union all
    select cte2.RoleID, replace(cte2.GroupNames,','+s.Value+',','') as l, s.ID ,s.Value
    from cte2
    join s on s.ID=cte2.ID+1
)
SELECT a.Role, a.Sort_Order, a.Parent, a.Parent_ID, a.Parent_URL, a.Child, a.Child_ID,a.Child_URL
FROM Config_View a
WHERE a.Role IN (
    Select Name from (
        Select distinct RoleID from cte2 where len(GroupNames)=0
    ) tempRoles
    join User_Role
    on tempRoles.RoleID = User_Role.ID
    ) 

这将是字符串变量sql的值,然后将其命名为:

SQLServerPreparedStatement pStmt = (SQLServerPreparedStatement) connection.prepareStatement(sql); 
pStmt.setStructured(1, "dbo.CategoryTableType", sourceTVPObject); 
ResultSet rs = stmt.executeQuery();