按选项参数构建SQL SELECT列

时间:2016-02-09 16:52:20

标签: sql sql-server tsql stored-procedures

我被要求创建一个存储过程,它将接受许多选项(目前有八个布尔值)来指示包含哪些列。

我可以为每种情况创建一个单独的SELECT语句,但是8²(八方)= 64个单独的select语句。再添加1个参数,我现在有9²= 81个单独的select语句。这很快就会增加。

我正在使用Microsoft的SQL Server Management Studio(SSMS),因为我不是一个强大的SQL编写器,它告诉我什么时候我做错了。

如果我构建一个动态SQL语句,我将失去SSMS的代码检查能力。

问:有没有办法使用参数值指定SELECT语句列?

这是一个非常粗略的例子,我尝试使用SQL Fiddle拼凑在一起:

http://sqlfiddle.com/#!3/5ef0f/1

架构:

create table Invoice 
(
    Id int IDENTITY(1,1) NOT NULL,
    Name varchar(20) NOT NULL,
    Retail decimal(9, 4) NOT NULL,
    Quoted decimal(9, 4) NOT NULL,
    TaxCodeId int NULL
);

create table TaxCode 
(
    Id int IDENTITY(1,1) NOT NULL,
    Name varchar(20) NOT NULL,
    Rate decimal(9, 4) NOT NULL
);

存储过程:

CREATE PROCEDURE TestProcedure
    (@showPrice bit, @showTaxRate bit) 
AS BEGIN
    SET NOCOUNT ON;

    SELECT 
        Invoice.Name,
        CASE WHEN @showPrice = 1 THEN Invoice.Retail, Invoice.Quoted, 
        END
        CASE WHEN @ShowTaxRate = 1 THEN TaxCode.Rate 
        END
    FROM 
        Invoice
    LEFT JOIN 
        TaxCode on Invoice.TaxCodeId = TaxCode.Id;
END;

2 个答案:

答案 0 :(得分:3)

你已经找到了两个选项和每个选项的缺点。

您可以使用:

  1. 动态SQL或
  2. IF逻辑决定执行哪个SELECT(64)。
  3. 没有别的办法。

    如果您担心失去SSMS的代码检查能力,可以在开发期间使用PRINT语句来查看动态查询的外观,并将该查询复制并粘贴到新的SSMS查询中以查看SSMS可能具有的建议

答案 1 :(得分:2)

一种方法是使用DECLARE @showPrice BIT = 1 ,@showTaxRate BIT = 0; DECLARE @sql NVARCHAR(MAX) = N'SELECT i.Name,i.Retail,i.Quoted,tc.Rate FROM Invoice i LEFT JOIN TaxCode tc ON i.TaxCodeId=tc.Id;'; IF @showPrice = 0 SET @sql = REPLACE(@sql, ',i.Retail,i.Quoted', ''); IF @showTaxRate = 0 SET @sql = REPLACE(@sql, ',tc.Rate', ''); EXEC dbo.sp_executesql @sql; (连接列列表或从列列表中排除)

DROP column

LiveDemo

第二种丑陋的方式是使用临时表和DECLARE @showPrice BIT = 1 ,@showTaxRate BIT = 0; SELECT i.Name,i.Retail,i.Quoted,tc.Rate INTO #temp FROM Invoice i LEFT JOIN TaxCode tc ON i.TaxCodeId=tc.Id; IF @showPrice = 0 ALTER TABLE #temp DROP COLUMN Retail, Quoted; IF @showTaxRate = 0 ALTER TABLE #temp DROP COLUMN Rate; -- if you use it within SP you need to wrap it with `EXEC` -- EXEC('ALTER TABLE #temp DROP COLUMN Rate;'); SELECT * FROM #temp;

context.CITies.Find(comId1, comId2);

LiveDemo2