AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 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 Dinâmico Parametrizado - Parâmetros Dinâmicos

  • 772

Temos uma situação em que efetivamente o mesmo relatório é solicitado por clientes diferentes, mas eles:

  1. Não quero todas as colunas
  2. Quer as colunas em uma ordem diferente da que naturalmente as temos
  3. Quer que eles sejam chamados de algo diferente do que temos armazenado ("Nº do cliente" vs "Número do cliente", por exemplo)

A intenção é facilitar o esforço necessário para acomodar essas solicitações de personalização. Atualmente, estamos em uma posição com algumas centenas de instâncias desses relatórios basicamente idênticos (excluindo essas diferenças superficiais). Eu estou olhando para ver se eu precisava de uma instância dessas Dynamicconsultas base por Parameterconjunto ou se eu poderia lidar com todos os parameterconjuntos possíveis por meio de 1 Stored Procedure. A esperança é também não ter que ter um monte de instâncias específicas de algum tipo de SSRS RDLarquivo ou SSIS DTSXpacote para lidar com essas mudanças. Que os dados saiam da Stored Procedureforma que precisamos que sejam exibidos/apresentados.

Vamos supor que eu construo um Dynamic SQL Commandonde a saída se parece com:

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

Ele é construído a partir de algumas partes diferentes usando algumas tabelas. As estruturas de tabela abaixo são mais pseudocódigos para transmitir as ideias, então ignore coisas como não há chaves primárias declaradas, etc ...

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 |
+----+------------------+------------+-------------+-------------+

O comando é construído usando o código abaixo:

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

Existe uma maneira de alterar dinamicamente os parâmetros configurados e passados ​​sem ter que criar um comando separado?

Eu gostaria de ser capaz de preencher [report].[ReportTemplateType].[WhereCondition]e [report].[ReportTemplateType].[WhereCondition]com um diferente WHEREe Parameters. Por exemplo, adicionar um terceiro columnem WHERE conditionalgo como Col4 = @TypeParameter. A única maneira que conheço de resolver isso é criar um diferente Stored Procedureonde tudo seja idêntico ao acima Stored Procedure, mas mudaríamos a última peça para:

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

Existe uma maneira de alterar dinamicamente os parâmetros configurados e passados ​​sem ter que criar um comando separado?

sql-server dynamic-sql
  • 3 3 respostas
  • 191 Views

3 respostas

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

    Muito longo para um comentário, então despejei isso para uma resposta.

    Minha preferência pessoal é que o SQL dinâmico (DSQL) nunca deve ser usado por código de produção que não seja de natureza administrativa . Eu uso o DSQL o tempo todo quando se trata de gerenciar ambientes, mas nenhum deles realmente exige um nível significativo de desempenho. No momento em que você começar a enviar o Dynamic SQL como código de produção , inevitavelmente terá problemas de desempenho . Nesse momento, as rodas saem porque o DSQL é notório para solucionar problemas. Obviamente, isso é apenas uma opinião e você é livre para fazer o que quiser, mas eu desencorajaria fortemente o uso de DSQL em qualquer código que você enviar para produção.

    Antes de ir mais longe neste caminho, eu recomendo a leitura, o que eu sinto é o artigo definitivo sobre SQL dinâmico, por Erland Sommarskog: The Curse and Blessings of Dynamic SQL

    É uma leitura muito boa; apenas esteja avisado que levará um pouco de tempo para digerir tudo.

    Vou pular da minha caixa de sabão agora....

    Quanto à sua pergunta:

    Existe uma maneira de alterar dinamicamente os parâmetros configurados e passados ​​sem ter que criar um comando separado?

    Sim, você pode precisar aninhar seu DSQL ou adicionar tabelas de relatório adicionais de acordo, mas apenas seus requisitos e abordagem ditarão o caminho apropriado. Se você é a pergunta mais urgente, e obviamente eu diria que não.

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

    Dos comentários:

    Eu acho que você precisa dar um passo para trás e olhar para o que você quer realmente alcançar com isso. Você está andando por um caminho com muitos problemas conhecidos. Para solução de problemas, desempenho, capacidade de manutenção e muitos outros, aconselho você a apenas criar vários procedimentos armazenados para cada tipo de consulta que deseja compilar e executá-los. Esses tipos de tabelas de fragmentos SQL vão levá-lo a um final ruim, pois a próxima pobre alma a herdar isso desejará um carma ruim contra você. – Jonathan Fit

    Concordo com @JonathanFite. Eu segui esse caminho antes e, no final, você acaba sendo forçado a criar vários procedimentos de qualquer maneira. Dado seu último comentário, eu diria que você está tentando fazer isso na área errada da sua pilha. Em vez de tentar tornar as consultas flexíveis o suficiente para lidar com todas as situações, sugiro que você gaste o tempo criando ou usando uma solução de relatórios existente que permita aos usuários personalizar a aparência dos relatórios (e salvar a personalização). Portanto, se quiserem alterar os nomes das colunas, ordem, exibição, etc., eles podem fazer isso sozinhos. – camba1

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

    Não há problema em usar dynamic Sqlna medida do possível "Blessing Part of Dynamic Sql".

    Eu não estou entrando muito nisso.

    Sua exigência em pequena escala,

    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'
    );
    

    Haverá UI onde você preencherá UserPrefReport. Não deve haver nenhum bug durante o preenchimento. Você preencherá o valor 'FirstName as [FName],MiddleName as [MName]'na mesma ordem que o usuário desejar.

    atualmente não há uso de Reportid.Ou você pode criar outra tabela TableorViewe referenciar Reportidaqui.Não é grande coisa.

    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;
    

    Sua exigência em grande escala,

    Isso significa que você também está dando ao usuário a facilidade de pesquisar nesses campos. E apenas esses campos devem ser preenchidos.

    Nesse caso, o design do UserPrefReport será dessa maneira,

    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;
    

    Em ambos os casos, a população de UserPrefReporté muito importante.

    Diga-me qual parte do seu requisito estou faltando no meu script ??

    • 0

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

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

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve