【问题标题】:Update table data by keeping only newest modification date and time of records w/ no duplicates通过仅保留记录的最新修改日期和时间来更新表数据,没有重复
【发布时间】:2016-05-07 11:55:16
【问题描述】:

我有以下 SQL 查询,它跟踪商品价格、日期和价格变化时间,并将值保存在名为 dbo.NewPriceLabel 的表中。

我试图让它只保留基于修改日期和时间的最新修改,并删除同一主键的旧值。 pk 是PLU

这是我当前的查询:

USE [ItemTable]
GO
/****** Object:  Table [dbo].[NewPriceLabel]    Script Date: 05/07/2016 03:46:58 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[NewPriceLabel](
    [PLU] [varchar](25) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
    [Description] [varchar](40) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [Sizes] [varchar](7) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [OldPrice] [real] NULL,
    [NewPrice] [real] NULL,
    [Datechange] [datetime] NOT NULL CONSTRAINT [NewPriceLabel_Datechange]  DEFAULT (getdate()),
    CONSTRAINT [PK_NewPriceLabel] PRIMARY KEY CLUSTERED (
        [PLU] ASC,
        [Datechange] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = ON) ON [PRIMARY]) ON [PRIMARY]

GO
SET ANSI_PADDING OFF

【问题讨论】:

  • 所以你需要一个触发器,当插入具有相同 PLU 的新行时删除旧记录?
  • 您问题中的“查询”只是表 DDL。如果表的目的是只保留最近 Datechange 的行,您应该从主键中删除 Datechange,以便每个 PLU 只有一行,然后您可以使用MERGE 语句插入,如果它没有' 尚不存在,仅当 Datechange 晚于当前值时才更新。
  • @gofr1:谢谢。你能给我看一个这个触发器的示例脚本吗
  • @DanGuzman:你能帮我写下这个 MERGE 语句吗?谢谢
  • @gofr1:使用此触发器时出现以下错误:消息 102,级别 15,状态 1,过程 TRG_AFTER_INS_UPD,第 9 行“END”附近的语法不正确。

标签: sql-server duplicates compare


【解决方案1】:

当插入具有相同 PLU 的新行时将删除旧记录的触发器:

CREATE TRIGGER TRG_AFTER_INS_UPD
ON yourTable
AFTER INSERT, UPDATE
AS
    DELETE y
    FROM yourTable y
    INNER JOIN inserted i 
        ON i.PLU = y.PLU AND i.Datechange > y.datechange

【讨论】:

  • 好吧,我的查询中没有看到任何 END .. 删除该触发器并创建新的。在底部添加 GO。更改您的实际名称。
  • 我进行了更正并重新创建了触发器,但我仍然得到重复的值。我正在尝试删除所有重复项,只保留最近的记录值
  • 我的荣幸!如果我的回答有帮助,请随时接受/点赞。
【解决方案2】:

由于您的要求是每个 PLU 只保留一行,我建议您从主键中删除 Datechange 并执行一次性删除以删除现有重复项:

--one-time delete
WITH dups AS (
    SELECT ROW_NUMBER() OVER(PARTITION BY PLU ORDER BY Datechange DESC) AS RowNum 
    )
DELETE FROM dups
WHERE RowNum > 1;

--remove Datechange from primary key
ALTER TABLE dbo.NewPriceLabel
    DROP CONSTRAINT PK_NewPriceLabel;
ALTER TABLE dbo.NewPriceLabel
    ADD CONSTRAINT PK_NewPriceLabel PRIMARY KEY (PLU);

如果您的传入数据包含Datechange 值,并且您只想在新的Datechange 比当前值更新时更新现有行,请考虑MERGE,下面是一个示例。

CREATE PROC dbo.MergeNewPriceLabel
     @PLU varchar(25)
    ,@Description varchar(40)
    ,@Sizes varchar(7) 
    ,@OldPrice real 
    ,@NewPrice real 
    ,@Datechange datetime
AS
SET NOCOUNT ON;

--source PLU with a Datechange older than current one are ignored
MERGE dbo.NewPriceLabel AS target
USING (
    SELECT 
          @PLU AS PLU
        , @Description AS Description
        , @Sizes AS Sizes
        , @OldPrice AS OldPrice
        , @NewPrice AS NewPrice
        , @Datechange AS Datechange
    ) AS source ON
    source.PLU = target.PLU
WHEN NOT MATCHED BY target THEN
    INSERT (
          PLU
        , Description
        , Sizes
        , OldPrice
        , NewPrice
        , Datechange)
    VALUES (
          @PLU
        , @Description
        , @Sizes
        , @OldPrice
        , @NewPrice
        , @Datechange
    )
WHEN MATCHED AND source.Datechange >= target.Datechange THEN
    UPDATE SET
          PLU = source.PLU
        , Description = source.Description
        , Sizes = source.Sizes
        , OldPrice = source.OldPrice
        , NewPrice = source.NewPrice
        , Datechange = source.Datechange;
GO

如果您在源数据中没有Datechange,并且只想在该行不存在时插入该行,如果存在则更新:

CREATE PROC dbo.MergeNewPriceLabel
     @PLU varchar(25)
    ,@Description varchar(40)
    ,@Sizes varchar(7) 
    ,@OldPrice real 
    ,@NewPrice real 
AS
SET NOCOUNT ON;

--assume source PLU data is newer than current row and update Datechanged with current timestamp
MERGE dbo.NewPriceLabel AS target
USING (
    SELECT 
          @PLU AS PLU
        , @Description AS Description
        , @Sizes AS Sizes
        , @OldPrice AS OldPrice
        , @NewPrice AS NewPrice
    ) AS source ON
    source.PLU = target.PLU
WHEN NOT MATCHED BY target THEN
    INSERT (
          PLU
        , Description
        , Sizes
        , OldPrice
        , NewPrice
        )
    VALUES (
          @PLU
        , @Description
        , @Sizes
        , @OldPrice
        , @NewPrice
    )
WHEN MATCHED THEN
    UPDATE SET
          PLU = source.PLU
        , Description = source.Description
        , Sizes = source.Sizes
        , OldPrice = source.OldPrice
        , NewPrice = source.NewPrice
        , Datechange = SYSDATETIME();

另外,我建议您避免使用realfloat 类型来存储货币值,因为这些数据类型是近似值,不能存储所有十进制值。请改用decimalnumericmoneysmallmoney

【讨论】:

  • 我在使用您的查询时收到以下错误:消息 102,级别 15,状态 1,过程 MergeNewPriceLabel,第 12 行“合并”附近的语法不正确。消息 156,级别 15,状态 1,过程 MergeNewPriceLabel,第 21 行关键字“AS”附近的语法不正确。
  • @Fadhl,您使用的是什么版本的 SQL Server?请添加适当的标签。 MERGE 是在 SQL Server 2008 中引入的,在 SQL 2005 及更早版本中不起作用。
猜你喜欢
  • 2018-09-23
  • 1970-01-01
  • 1970-01-01
  • 2019-06-15
  • 1970-01-01
  • 2020-05-10
  • 2019-12-20
  • 2020-04-21
  • 2021-03-18
相关资源
最近更新 更多