AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 242755
Accepted
Kirk Saunders
Kirk Saunders
Asked: 2019-07-13 05:19:42 +0800 CST2019-07-13 05:19:42 +0800 CST 2019-07-13 05:19:42 +0800 CST

参数化动态 TSQL - 动态参数

  • 772

我们有一种情况,不同的客户实际上要求相同的报告,但他们:

  1. 不想要所有的列
  2. 希望列的顺序与我们自然拥有的顺序不同
  3. 希望它们被称为不同于我们存储方式的名称(例如“客户编号”与“客户编号”)

目的是减轻适应这些定制请求所需的工作量。我们目前处于这些基本相同报告的数百个实例的位置(不包括这些表面差异)。我想看看我是否需要Dynamic每组这些基本查询的一个实例,Parameter或者我是否可以parameter通过 1 处理所有可能的集合Stored Procedure。希望也不必拥有一堆特定SSRS RDL文件或SSIS DTSX包的特定实例来处理这些更改。数据将来自Stored Procedure我们需要显示/呈现的数据。

让我们假设我构建了一个Dynamic SQL Command输出看起来像这样的地方:

SELECT
Col1 AS 'Alias1',
Col2 AS 'Alias2',
Col3 AS 'Alias3'
FROM View
WHERE DateCol >= @StartDate
AND DateCol < @EndDate

它是由几个不同的部分使用几个表构建的。下面的表结构是更多的伪代码来理解这些想法,所以请忽略诸如没有声明主键之类的东西......

CREATE TABLE [report].[ReportTemplate]
(
    ID INT NOT NULL, --(Primary Key)
    ReportName VarChar(100) NOT NULL,
    ReportTypeID INT NOT NULL --(FK To report.ReportTemplateType.ID)
)

CREATE TABLE [report].[ReportTemplateType]
(
    ID INT NOT NULL, --(Primary Key)
    Name VarChar(50), --(Unique Constraint)
    BaseCommand VarChar(2000), --Holds FROM and JOIN clauses
    WhereCommand VarChar(2000), --Holds WHERE Clause
    WhereCommandParameters VarChar(2000), --Holds declaration of the parameters
)

CREATE TABLE [report].[ReportTemplateColumnDetails]
(
    ID INT NOT NULL, --(Primary Key)
    ReportTemplateID INT NOT NULL, --(FK to report.ReportTemplate.ID)
    ColumnName VarChar(256) NOT NULL,
    ColumnAlias VarChar(256) NULL, --Have logic handle blank vs NULL values
    ColumnOrder SmallInt NOT NULL
)
+----+-------------------+--------------+
| ID |    ReportName     | ReportTypeID |
+----+-------------------+--------------+
|  1 | Customer 1 Status |            1 |
|  2 | Customer 1 Sales  |            2 |
+----+-------------------+--------------+


+----+--------+-----------------+------------------------------------------------------------------------------+-------------------------------------------------------------------+
| ID |  Name  |   BaseCommand   |                                WhereCondition                                |                     WhereConditionParameters                      |
+----+--------+-----------------+------------------------------------------------------------------------------+-------------------------------------------------------------------+
|  1 | Status | FROM StatusView | WHERE DateCol >= @StartDate AND DateCol < @EndDate                           | @StartDate DATEIME, @EndDate DateTime                             |
|  2 | Sales  | FROM SalesView  | WHERE DateCol >= @StartDate AND DateCol < @EndDate AND Col4 = @TypeParameter | @StartDate DATEIME, @EndDate DateTime, @TypeParameter VarChar(20) |
+----+--------+-----------------+------------------------------------------------------------------------------+-------------------------------------------------------------------+

+----+------------------+------------+-------------+-------------+
| ID | ReportTemplateID | ColumnName | ColumnAlias | ColumnOrder |
+----+------------------+------------+-------------+-------------+
|  1 |                1 | Col1       | Alias1      |           1 |
|  2 |                1 | Col2       | Alias2      |           2 |
|  3 |                1 | Col3       | Alias3      |           3 |
|  4 |                2 | Col4       | Alias1      |           1 |
|  5 |                2 | Col5       | Alias2      |           2 |
|  6 |                2 | Col6       | Alias3      |           3 |
+----+------------------+------------+-------------+-------------+

该命令是使用以下代码构建的:

CREATE PROCEDURE [report].[ExecuteReportTemplate] (@ReportName VarChar(50))
AS
BEGIN
    DECLARE @SQLCommand VarChar(MAX) = 'SELECT ',
            @FirstColumnAdded BIT = 0,
            @BaseCommand VarChar(2000),
            @WhereCondition VarChar(2000),
            @WhereConditionParameters VarChar(2000)

    SELECT @BaseCommand = RTT.BaseCommand,
    @WhereCondition = RTT.WhereCommand, 
    @WhereConditionParameters = RTT.WhereCommandParameters 
    FROM [report].[ReportTemplateType] RTT
        INNER JOIN [report].[ReportTemplate] RT
            ON RTT.ID = RT.ReportTypeID
    WHERE RT.Name = @ReportName

    DECLARE @ColumnName VarChar(256),
            @ColumnAlias VarChar(256)

    DECLARE ColumnCursor CURSOR FOR
    SELECT ColumnName,
    ColumnAlias
    FROM [report].[ReportTemplateColumnDetails]
    ORDER BY ColumnOrder

    FETCH NEXT FROM ColumnCursor INTO @ColumnName, @ColumnAlias

    WHILE (@@FETCH_STATUS = 0)
    BEGIN
        --Add a comma inbetween columns, does not happen on the first one
        IF(@FirstColumnAdded = 1)
        BEGIN
            SET @SQLCommand = @SQLCommand + ', '
        END
        ELSE
        BEGIN
            SET @FirstColumnAdded = 1
        END

        --Adds the column into the list
        SET @SQLCommand = @SQLCommand + @ColumnName

        --If we have been provided an alias, set the alias
        IF(@ColumnAlias IS NULL OR LTRIM(RTRIM(@ColumnAlias)) = '')
        BEGIN
            @SQLCommand = @SQLCommand + 'AS ''' + @ColumnAlias + ''' '
        END
    END

    CLOSE ColumnCursor
    DEALLOCATE ColumnCursor

    --Now Add The Base Command
    SELECT @SQLCommand = @SQLCommand + ' ' + @BaseCommand + ' ' + @WhereCommand

    EXECUTE sp_executesql @sqlCommand, @WhereConditionParameters
        @StartDate = '2019-01-01', 
        @EndDate = GETDATE()
END

有没有办法动态更改配置和传入的参数而无需构建单独的命令?

我希望能够用不同的and填充[report].[ReportTemplateType].[WhereCondition]and 。例如在类似的东西中添加第三个。我知道解决这个问题的唯一方法是创建一个不同的地方,其中所有内容都与上述相同,但我们会将最后一块更改为:[report].[ReportTemplateType].[WhereCondition]WHEREParameterscolumnWHERE conditionCol4 = @TypeParameterStored ProcedureStored Procedure

EXECUTE sp_executesql @sqlCommand, @WhereConditionParameters
        @StartDate = '2019-01-01', 
        @EndDate = GETDATE(),
        @TypeParameter = 'SomeStringValue'

有没有办法动态更改配置和传入的参数而无需构建单独的命令?

sql-server dynamic-sql
  • 3 3 个回答
  • 191 Views

3 个回答

  • Voted
  1. Best Answer
    John Eisbrener
    2019-07-13T07:49:50+08:002019-07-13T07:49:50+08:00

    评论太长了,所以我把它抛给了一个答案。

    我个人的偏好是动态 SQL (DSQL) 不应该被非管理性质的生产代码使用。在管理环境时,我一直使用 DSQL,但这些都不需要任何显着水平的性能。当您开始将 Dynamic SQL 作为生产代码推出时,您将不可避免地遇到性能问题。在那一刻,轮子脱落了,因为 DSQL 是出了名的故障排除。显然,这只是一种意见,你可以自由地做你想做的事,但我强烈反对在你推送到生产的任何代码中使用 DSQL。

    在你走得更远之前,我建议你阅读一下我认为是 Erland Sommarskog 撰写的关于动态 SQL 的权威文章:动态 SQL的诅咒和祝福

    这真是一本好书;请注意,消化这一切需要一点时间。

    我现在要跳下我的肥皂盒......

    至于你的问题:

    有没有办法动态更改配置和传入的参数而无需构建单独的命令?

    是的,您可能需要嵌套您的 DSQL或相应地添加额外的报告表,但只有您的要求和方法才能决定适当的路径。 如果你是更紧迫的问题,显然我会说不。

    • 2
  2. mv ٠〳comment ٠〳answer
    2020-10-30T08:46:29+08:002020-10-30T08:46:29+08:00

    来自评论:

    我认为你需要退后一步,看看你想用这个实际实现什么。您正走在一条有许多已知问题的道路上。对于故障排除、性能、可维护性和许多其他问题,我建议您为要编译和运行的每种查询类型创建多个存储过程。这些类型的 SQL 片段表将导致你走向一个糟糕的结局,因为下一个继承它的可怜的灵魂会希望对你产生不好的业力。——乔纳森·菲特

    我同意@JonathanFite。之前我已经走上了这条路,最终你最终还是被迫创建了多个程序。鉴于您的最后评论,我想说您正试图在堆栈的错误区域执行此操作。与其尝试使查询足够灵活以处理所有情况,我建议您花时间构建或使用现有的报告解决方案,该解决方案允许用户自定义报告的外观(并保存自定义)。因此,如果想更改列名、顺序、显示等。他们可以自己做。– 坎巴1

    • 1
  3. KumarHarsh
    2019-07-16T03:36:14+08:002019-07-16T03:36:14+08:00

    可以使用dynamic Sql,只要它在"Blessing Part of Dynamic Sql".

    我没有深入了解它。

    您对小规模的要求,

    CREATE TABLE #UserPrefReport
    (Userid       INT NOT NULL, 
     Reportid     INT NOT NULL, 
     TableorView  VARCHAR(100) NOT NULL, 
     AliasColumns VARCHAR(5000) NOT NULL, 
     OrderBy      VARCHAR(100)
    );
    INSERT INTO #UserPrefReport
    (Userid, 
     Reportid, 
     TableorView, 
     AliasColumns, 
     OrderBy
    )
    VALUES
    (1, 
     1, 
     'DimCustomer', 
     'FirstName as [First Name],MiddleName as [Middle Name]', 
     'firstname asc, MiddleName desc'
    ),
    (2, 
     1, 
     'DimCustomer', 
     'FirstName as [FName],MiddleName as [MName]', 
     'firstname asc, MiddleName desc'
    );
    

    您将在其中填充 UI 。填充UserPrefReport时不应出现任何错误。您将'FirstName as [FName],MiddleName as [MName]'按照用户期望的相同顺序填充值。

    目前没有使用Reportid。或者你可以在这里创建另一个表TableorView并参考Reportid。这没什么大不了的。

    DECLARE @Userid INT= 1;-- parameter of SP
    DECLARE @TableorView VARCHAR(100)= 'DimCustomer';-- parameter of SP
    -- Local variable of SP below
        DECLARE @OrderBy VARCHAR(100);
        DECLARE @Sql NVARCHAR(MAX)= '';
        DECLARE @Cols VARCHAR(MAX)= '';
    
        SELECT @Cols = AliasColumns, 
               @OrderBy = OrderBy
        FROM #UserPrefReport
        WHERE userid = @Userid
              AND TableorView = @TableorView;
        SET @Sql = N'select ' + @Cols + ' from ' + @TableorView + ' order by ' + @OrderBy + '';
        PRINT @Sql;
        EXEC sp_executesql 
             @Sql;
        DROP TABLE #UserPrefReport;
    

    您对大规模的要求,

    这意味着您还为用户提供了搜索这些字段的便利。并且只应填充这些字段。

    在这种情况下,UserPrefReport 的设计将采用这种方式,

    CREATE TABLE #UserPrefReport1
    (Userid       INT NOT NULL, 
     TableorView  VARCHAR(100) NOT NULL, 
     colname      VARCHAR(100) NOT NULL, 
     AliasColumns VARCHAR(100) NOT NULL
    );
    INSERT INTO #UserPrefReport1
    (Userid, 
     TableorView, 
     colname, 
     AliasColumns
    )
    VALUES
    (1, 
     'DimCustomer', 
     'FirstName', 
     '[First Name]'
    ),
    (1, 
     'DimCustomer', 
     'MiddleName', 
     '[Middle Name]'
    ),
    (2, 
     'DimCustomer', 
     'FirstName', 
     '[FName]'
    ),
    (2, 
     'DimCustomer', 
     'MiddleName', 
     '[MName]'
    );
    SELECT *
    FROM #UserPrefReport1;
    
    DROP TABLE #UserPrefReport1;
    

    在这两种情况下,人口UserPrefReport都是非常重要的。

    告诉我我的脚本中缺少您的哪一部分要求?

    • 0

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve