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 / 46672
Accepted
Hani El Mouallem
Hani El Mouallem
Asked: 2013-07-20 03:56:18 +0800 CST2013-07-20 03:56:18 +0800 CST 2013-07-20 03:56:18 +0800 CST

Após os gatilhos de atualização que lidam com atualizações de várias linhas

  • 772

Atualmente trabalhando em um projeto de auditoria de banco de dados baseado em triggers que são disparadas na atualização de tabelas específicas. Os gatilhos gravam as alterações em uma tabela; informações gravadas são: nome da tabela, coluna atualizada, timestamp, usuário, valor antigo e novo valor.

Os gatilhos funcionam bem com atualizações únicas, mas quando se trata de atualizações de várias linhas, não estão funcionando.

Meu código está assim:

IF (UPDATE(Priority))  
BEGIN
    SET @UpdatedColumn = 'Priority'
    INSERT INTO dbo.AuditTable
        ( [TableName] ,
          [Source] ,
          [RecordId] ,
          [User] ,
          [TimeStamp] ,
          [UpdatedColumn] ,
          [OldValue] ,
          [NewValue]
        )
    SELECT 
        N'BookingItem' , -- TableName - nvarchar(max)
        (SELECT CODE FROM TBL_LEG_SOURCE 
                     INNER JOIN INSERTED INS ON LEG_SOURCE_ID = INS.SourceId) ,
        INS.Id , -- RecordId - bigint
        (SELECT USERNAME FROM INSERTED 
                     INNER JOIN TBL_USER 
                     ON ModifiedById = USER_ID) , -- User - nvarchar(max)
        GETDATE() , -- TimeStamp - datetime
        @UpdatedColumn , -- UpdatedColumn - nvarchar(max)
        DEL.Priority , -- OldValue - nvarchar(max)
        INS.Priority  -- NewValue - nvarchar(max)
    FROM 
        INSERTED INS INNER JOIN DELETED DEL ON INS.Id = DEL.Id
    WHERE
        (
            (INS.Priority <> DEL.Priority)
            OR (INS.Priority IS NULL AND DEL.Priority IS NOT NULL)
            OR (INS.Priority IS NOT NULL AND DEL.Priority IS NULL)
        )
END

Mensagem de erro:

Msg 512, Nível 16, Estado 1, Procedimento MyTrigger, Linha 818 A
subconsulta retornou mais de 1 valor. Isso não é permitido quando a subconsulta segue =, !=, <, <= , >, >= ou quando a subconsulta é usada como uma expressão.

Alguma sugestão sobre como corrigir meu gatilho para lidar com operações de várias linhas?

sql-server sql-server-2012
  • 2 2 respostas
  • 16859 Views

2 respostas

  • Voted
  1. Aaron Bertrand
    2013-07-20T06:21:51+08:002013-07-20T06:21:51+08:00

    Aqui está como corrigir os erros, usando junções adequadas (e se isso não for "rápido o suficiente", observe sua indexação):

    INSERT dbo.AuditTable
    (
      [TableName],
      [Source],
      [RecordId],
      [User],
      [TimeStamp],
      [UpdatedColumn],
      [OldValue],
      [NewValue]
    )
    SELECT 
      N'BookingItem', -- TableName - nvarchar(max)
      ls.CODE,
      INS.Id, -- RecordId - bigint
      u.USERNAME,
      GETDATE(), -- TimeStamp - datetime
      @UpdatedColumn, -- UpdatedColumn - nvarchar(max)
      DEL.Priority, -- OldValue - nvarchar(max)
      INS.Priority  -- NewValue - nvarchar(max)
    FROM 
      INSERTED AS INS 
    INNER JOIN 
      DELETED AS DEL ON INS.Id = DEL.Id
    INNER JOIN 
      dbo.TBL_LEG_SOURCE AS ls ON ls.LEG_SOURCE_ID = INS.SourceId
    INNER JOIN
      dbo.TBL_USER AS u ON INS.ModifiedById = u.USER_ID
    WHERE
    (
      (INS.Priority <> DEL.Priority)
      OR (INS.Priority IS NULL AND DEL.Priority IS NOT NULL)
      OR (INS.Priority IS NOT NULL AND DEL.Priority IS NULL)
    );
    

    No entanto, acho que é muito tolo executar mais de 50 inserções diferentes dessa variedade para capturar cada alteração de coluna. Por que não apenas criar uma tabela com colunas para hora e nome da tabela (você não precisa armazenar o nome de usuário porque sempre pode procurar isso mais tarde) e, sempre que houver uma atualização, armazenar a versão antiga e a nova da linha? Você pode até usar um SEQUENCEpara garantir que possa identificar o conjunto de linhas que foram modificadas juntas (já que o timestamp pode não ser exclusivo o suficiente para fazer isso).

    CREATE SEQUENCE dbo.AuditSequence
      AS INT START WITH 1 INCREMENT BY 1;
    
    CREATE TABLE dbo.AuditData
    (
      AuditSequenceID INT,
      TableName SYSNAME,
      [TimeStamp] DATETIME,
      RowState CHAR(1), -- e.g. 'B' = before, 'A' = after
      ... all your 50 columns, including ModifidById ...
    );
    

    Agora no seu gatilho:

    CREATE TRIGGER dbo.MyTrigger
      ON dbo.BookingItem
      FOR UPDATE
    AS
    BEGIN
      SET NOCOUNT ON;
    
      DECLARE @as INT = NEXT VALUE FOR dbo.AuditSequence,
              @now DATETIME = CURRENT_TIMESTAMP;
    
      INSERT dbo.AuditData(AuditSequenceID, TableName, [TimeStamp], RowState,
        ... the rest of your 50 columns)
      SELECT @as, N'BookingItem', @now, 'B', * FROM deleted;
    
      INSERT dbo.AuditData(AuditSequenceID, TableName, [TimeStamp], RowState,
        ... the rest of your 50 columns)
      SELECT @as, N'BookingItem', @now, 'A', * FROM inserted;
    END
    GO
    

    Agora, escreva consultas complicadas contra essa estrutura de auditoria muito mais simples que é ineficiente e tente rastrear exatamente quais colunas foram alteradas e tudo mais. É muito melhor pagar esse preço ao revisar dados de auditoria do que pagar esse preço em cada operação de atualização.

    • 9
  2. Best Answer
    Sebastian Meine
    2013-07-20T06:24:31+08:002013-07-20T06:24:31+08:00

    Ambas as subconsultas na consulta que você mostra juntam-se a INSERTED sem fazer uma agregação ou um top(1). Portanto, ambos potencialmente retornam mais de uma linha. em vez de ingressar na tabela INSERTED novamente, apenas faça referência à coluna diretamente. Com isso a segunda consulta ficaria assim:

    (SELECT U.USERNAME FROM TBL_USER U WHERE INS.ModifiedById = U.USER_ID)
    

    A mudança para o outro é semelhante.

    • 4

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

    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

    Conceder acesso a todas as tabelas para um usuário

    • 5 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
    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
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +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