2016-12-01 36 views
0

我正在研究一个存储过程,它获取每个公司的数据并执行SELECT INTO语句。目前,我有一个if条件,它只会对选定的公司运行。然而,在这之后我有很多的SELECT INTO创建的联合声明其联盟中的所有表:基于参数的具有联合的动态查询

SELECT * INTO ##LevelAll FROM ##Levela 
UNION 
SELECT * FROM ##Levelb 
UNION 
SELECT * FROM ##Levelc 
UNION 
SELECT * FROM ##Leveld 
UNION 
SELECT * FROM ##Levele 

我遇到的问题是,如果我没有运行C级查询,然后我上面的代码将失败。

有没有一种方法,我可以动态地查询这...基于我运行存储过程4的公司? (我可以运行多个公司'CompanyA,CompanyB,CompanyC)。

+1

公司与关卡有什么关系?不要告诉我你将每个公司的记录存储在一张单独的表格中!如果是这样,重新设计数据库。 –

+0

您是否还在条件中创建临时表...如果您在存储过程开始时将它们声明为if ... – Hackerman

+1

然后始终运行C级查询,以便永远不会失败。你可以填充任何东西('IF @doC然后SELECT ... INTO ... FROM; ELSE SELECT TOP(0)... INTO ... FROM;'或类似的方法来创建一个空表模式)。如果您可以通过使其他代码更复杂来避免动态查询,那么通常还是会付出代价的。然而,根据@Gordon,你可能会更好,因为预先设计的更好,所以这种查询不需要首先完成。 –

回答

0

正如在评论中提到的那样,只要简单地改变你的数据库结构就可以真正受益。

但如果你不能,你就可以避免动态SQL和大量重复的代码使用参数化top (x) percent这里您指定1000取决于如果你想从union与否的一部分返回数据上。

我也想说这看起来好像你不会在意在此查询重复的“水平”是不同的公司,所以你可以使用union all代替union这将加快你的表现:

declare @a int = 100 
     ,@b int = 100 
     ,@c int = 0  -- No records from table c will be returned. 
     ,@d int = 100 
     ,@e int = 100; 

SELECT TOP (@a) PERCENT * 
INTO ##LevelAll 
FROM ##Levela 
UNION ALL 
SELECT TOP (@b) PERCENT * 
FROM ##Levelb 
UNION ALL 
SELECT TOP (@c) PERCENT * 
FROM ##Levelc 
UNION ALL 
SELECT TOP (@d) PERCENT * 
FROM ##Leveld 
UNION ALL 
SELECT TOP (@e) PERCENT * 
FROM ##Levele; 
0

我已经基于通过存储过程传递的变量构建了一个动态查询。我的文字被评论为正在发生的事情。

首先,您需要一个表值函数来分割您的参数,以便其中列出的每个公司都是生成的返回表中的一行。这里是低于功能,你需要你的数据库上创建此:

CREATE FUNCTION [dbo].[ufnSplit] 
( 
    @string VARCHAR(MAX), 
    @delimiter CHAR(1) 
) 
RETURNS @output TABLE(Item VARCHAR(MAX) 
) 
BEGIN 
    DECLARE @start INT, @end INT 
    SELECT @start = 1, @end = CHARINDEX(@delimiter, @string) 
    WHILE @start < LEN(@string) + 1 BEGIN 
     IF @end = 0 
      SET @end = LEN(@string) + 1 

     INSERT INTO @output (Item) 
     VALUES(SUBSTRING(@string, @start, @end - @start)) 
     SET @start = @end + 1 
     SET @end = CHARINDEX(@delimiter, @string, @start) 

    END 
    RETURN 
END 

接下来在存储过程中,我们使用此功能将参数分成数行,到一个临时表称为#Companies。然后,我们使用一个循环来通过#Companies来创建您的UNION查询(或者,如果只有一个值)。再次,我已经对我正在做的事情做了很多评论。

USE [DatabaseName] 
GO 

CREATE PROCEDURE uspLevelReports 
@param VARCHAR(MAX) 

/* Use this for testing your parameters: 
EXEC uspLevelReports @param = 'A,B,D' 
*/ 

AS 

BEGIN TRY 


IF OBJECT_ID('tempdb..#Companies') IS NOT NULL 
DROP TABLE #Companies 

-- use the split function to put each company into a table, and assign it a row number (necessary for the loop below) 
SELECT 
Item 
,ROW_NUMBER() OVER(ORDER BY Item ASC) AS RowNo 
INTO #Companies 
FROM dbo.ufnSplit(@param,',') 


-- Select below is for testing so you can see the effect: 
-- SELECT * FROM #Companies 

-- Create the basic query here, with the company suffix 
DECLARE @sql NVARCHAR(4000) = 'SELECT * From tempdb..##Level' 

-- Start to loop through #Companies, for each row no higher than 1, a union will be added 
-- First, tell the loop where to start and end: 
DECLARE @RowNo INT = 1 -- Your starting RowNo, should always be 1 so won't do a MIN() here 
DECLARE @MaxNo INT = (-- The highest RowNo in #Companies 
    SELECT 
    MAX(RowNo) 
    FROM #Companies 
    ) 
DECLARE @originalSQL NVARCHAR(4000) = @sql -- @Sql will be modified in the loop but we still need the original form to keep adding to each union if one is there 

WHILE @RowNo <= @MaxNo -- we will increase the value of @RowNo by 1 each time,the loop will break when @RowNo gets higher than @MaxNo 
BEGIN 

-- Find the company that corresponds to the @RowNo value in #Companies and add it to a variable: 
DECLARE @suffix VARCHAR(100) = (
    SELECT 
    Item 
    FROM #Companies 
    WHERE RowNo = @RowNo) 

IF @RowNo = @MaxNo -- If statement for the final Item in #Companies, this stops us adding UNION where we've finished the query 
    SET @sql += @suffix 
ELSE 
    SET @sql += @suffix + ' UNION ' + @originalSQL; 

SET @RowNo += 1 -- Add one to move to next RowNo in #Companies 

PRINT @sql -- This is for testing so you can see in Messages how the query is being built each loop 

END 

PRINT 'Final query: ' + @sql -- This is for testing so you can see in Messages what your final query is 



-- Create your level all table 
IF OBJECT_ID('tempdb..##LevelAll') IS NOT NULL 
DROP TABLE ##LevelAll 

-- You need to create your ##LevelAll table with all the columns needed, so amend them with their datatypes below mine is just for example: 

CREATE TABLE ##LevelAll(
Company CHAR(1) 
,value INT 
) 
--- insert into your level all table 
INSERT INTO ##LevelAll 
-- by executing the statement inside your string variable 
exec sp_executesql @sql 
-- publish the results 
SELECT * FROM ##LevelAll 

END TRY 

BEGIN CATCH 

    -- Your error trapping variables 

END CATCH 
+0

谢谢,但这不是我所要求的。基本上我试图执行一个联合声明,但如果参数没有该公司该代码没有执行,所以我基本上执行一个UNION的表不存在,因为代码执行每个公司的SELECT INTO语句。 – a415