Sql server 更新表格数据,只保留记录的最新修改日期和时间,不重复
我有以下SQL查询,它跟踪商品价格、日期和价格变化时间,并将值保存在名为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
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和早期版本中不起作用。