简体   繁体   English

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

[英]Optimizing SQL query with cte and variable inputs

I am trying to run the following SQL script using Java and am getting issues with no resultset from JDBCTemplate. 我正在尝试使用Java运行以下SQL脚本,并且从JDBCTemplate获得没有结果集的问题。 I thought about reducing it using functions/stored procedures and would like some help with it: 我考虑过使用函数/存储过程来减少它,并希望对此有所帮助:

SQL - first part: 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');  

Second part: 第二部分:

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

I was thinking first part can be done in a stored procedure. 我当时认为第一部分可以在存储过程中完成。 I did read here ( stored procedure with variable number of parameters ) about making a table from a list of variables but am not sure how to do set those variables in a loop like i am doing from above (1,Variable1 etc.). 我确实读过这里( 具有可变数量的参数的存储过程 ),关于如何从变量列表中创建表,但不确定如何像我从上面那样(1,Variable1等)在循环中设置这些变量。

I think the second part can be by itself? 我认为第二部分可以单独存在吗?

So my updated query might be: 所以我更新的查询可能是:

  1. Call stored procedure (variable1, ..., variablex); 调用存储过程(variable1,...,variablex);
  2. SQL part 2? SQL第2部分?

If anyone can help that would be great! 如果有人可以帮助,那就太好了!

It's possible to do this in two seperate batches, but only if you can ensure that the first batch runs in session scope, and not in a nested batch ( eg via sp_executesql ). 可以在两个单独的批次中执行此操作,但前提是您可以确保第一个批次在会话范围内运行,而不是在嵌套的批次中运行(例如,通过sp_executesql)。 Temp tables created in nested batches, like stored procedures or prepared statements are automatically destroyed at the end of the nested batch. 在嵌套批处理中创建的临时表(如存储过程或预准备语句)会在嵌套批处理结束时自动销毁。 So it depends on how you call it. 因此,这取决于您如何称呼它。 My guess is that a PreparedStatement won't work. 我的猜测是,PreparedStatement无法正常工作。

The right way to do this is probably to use a stored procedure with a table-valued parameter, or a JSON (for SQL 2016+), or XML parameter and parses it in the stored procedure body. 正确的方法可能是使用具有表值参数或JSON(对于SQL 2016+)或XML参数的存储过程,然后在存储过程主体中对其进行解析。 See https://docs.microsoft.com/en-us/sql/connect/jdbc/using-table-valued-parameters?view=sql-server-2017 请参阅https://docs.microsoft.com/zh-cn/sql/connect/jdbc/using-table-valued-parameters?view=sql-server-2017

You can also use a TSQL batch instead of a stored procedure and bind a Table-Valued Parameter, or a NVarchar(max) parameter containing JSON. 您还可以使用TSQL批处理代替存储过程,并绑定表值参数或包含JSON的NVarchar(max)参数。

With a TVP you could simply use a batch like: 使用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
    ) 

That would be the value of the string variable sql , and then call it something like: 那将是字符串变量sql的值,然后将其命名为:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM