Sql server 更新表格数据,只保留记录的最新修改日期和时间,不重复

Sql server 更新表格数据,只保留记录的最新修改日期和时间,不重复,sql-server,duplicates,compare,Sql Server,Duplicates,Compare,我有以下SQL查询,它跟踪商品价格、日期和价格变化时间,并将值保存在名为dbo.NewPriceLabel的表中 我试图使它只保留基于修改日期和时间的最新修改,并删除相同主键的旧值。主键是PLU 以下是我当前的查询: USE [ItemTable] GO /****** Object: Table [dbo].[NewPriceLabel] Script Date: 05/07/2016 03:46:58 ******/ SET ANSI_NULLS ON GO SET QUOTED_I

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

我试图使它只保留基于修改日期和时间的最新修改,并删除相同主键的旧值。主键是
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的新行时,将删除旧记录的触发器:

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

当插入具有相同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

由于您的要求是每个
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);

如果传入的数据包含<代码>笪特昌锷< /代码>值,并且只有当新<代码>笪特昌锷< /> >比当前值更新时,才想更新现有行,请考虑<代码>合并< /C> >,下面是一个例子。

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

另外,我建议您避免使用
real
float
类型来存储货币值,因为这些数据类型是近似的,不能存储所有十进制值。使用
decimal
numeric
money
smallmoney

由于您的要求是每个
PLU
只维护一行,因此我建议您从主键中删除
日期更改
,并执行一次性删除以删除现有重复项:

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

如果传入的数据包含<代码>笪特昌锷< /代码>值,并且只有当新<代码>笪特昌锷< /> >比当前值更新时,才想更新现有行,请考虑<代码>合并< /C> >,下面是一个例子。

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


另外,我建议您避免使用
real
float
类型来存储货币值,因为这些数据类型是近似的,不能存储所有十进制值。使用
decimal
numeric
money
smallmoney

因此,当插入具有相同PLU的新行时,您需要一个触发器来删除旧记录?问题中的“查询”只是表DDL。如果表的目的是仅保留具有最新Datechange的行,则应该从主键中删除Datechange,以便每个PLU只有一行,然后可以使用
MERGE
语句插入尚未存在的行,并仅在Datechange晚于当前值时更新。@gofr1:谢谢。你能给我看一下这个的脚本样本吗trigger@DanGuzman:您可以通过编写脚本来帮助我处理此合并语句吗。Thanks@gofr1:使用此触发器时,我遇到以下错误:Msg 102,级别15,状态1,过程TRG_AFTER_in_UPD,第9行靠近“END”的语法不正确。因此,您需要一个触发器,当插入具有相同PLU的新行时,该触发器将删除旧记录?您问题中的“查询”只是表DDL。如果表的目的是仅保留具有最新Datechange的行,则应该从主键中删除Datechange,以便每个PLU只有一行,然后可以使用
MERGE
语句插入尚未存在的行,并仅在Datechange晚于当前值时更新。@gofr1:谢谢。你能给我看一下这个的脚本样本吗trigger@DanGuzman:您可以通过编写脚本来帮助我处理此合并语句吗。Thanks@gofr1:使用此触发器时,我遇到以下错误:Msg 102,级别15,状态1,过程TRG\u-AFTER\u-INS\u-UPD,第9行“END”附近的语法不正确。嗯,我在查询中看不到任何结尾。。放下那个触发器,创建新的。在底部添加GO。更改实际名称上的表。我进行了更正并重新创建了触发器,但仍然得到重复的值。我正在尝试删除所有副本,只保留最新的记录值,我很高兴!如果我的回答有帮助,请随意接受/投票。好吧,我看不出我的问题有任何结果。。放下那个触发器,创建新的。在底部添加GO。更改实际名称上的表。我进行了更正并重新创建了触发器,但仍然得到重复的值。我正在尝试删除所有副本,只保留最新的记录值,我很高兴!如果我的答案有帮助,请随意接受/投票。我在使用您的查询时遇到以下错误:Msg 102,级别15,状态1,过程MergeNewPriceLabel,第12行“MERGE”附近的语法不正确。Msg 156,级别15,状态1,过程MergeNewPriceLabel,第21行关键字“AS”附近的语法不正确。@Fadhl,您使用的是什么版本的SQL Server?请添加相应的标签<代码>合并是在SQL Server 2008中引入的,在SQL 2005和早期版本中不起作用。在使用您的查询时,我遇到以下错误:Msg 102,级别15,状态1,过程MergeNewPriceLabel,第12行“MERGE”附近的语法不正确。Msg 156,级别15,状态1,过程MergeNewPriceLabel,第21行关键字“AS”附近的语法不正确。@Fadhl,您使用的是什么版本的SQL Server?请添加相应的标签<代码>合并是在SQL Server 2008中引入的,在SQL 2005和早期版本中不起作用。