通过比较日期进行SQL更新或插入

通过比较日期进行SQL更新或插入,sql,sql-server,Sql,Sql Server,我正在尝试进行更新或插入,但我不确定在不使用循环的情况下这是否可行。以下是一个例子: 比如,我在下面的SQL中加入了两个表:tblCompany和tblOrders SELECT CompanyID, CompanyName, c.LastSaleDate, o.SalesOrderID, o.SalesPrice , DATEADD(m, -6, GETDATE()) AS DateLast6MonthFromToday FROM dbo.tblCompany c CROSS APPLY (

我正在尝试进行更新或插入,但我不确定在不使用循环的情况下这是否可行。以下是一个例子:

比如,我在下面的SQL中加入了两个表:tblCompany和tblOrders

SELECT CompanyID, CompanyName, c.LastSaleDate, o.SalesOrderID, o.SalesPrice
, DATEADD(m, -6, GETDATE()) AS DateLast6MonthFromToday
FROM dbo.tblCompany c
CROSS APPLY (
    SELECT TOP 1 SalesOrderID, SalesPrice
    FROM dbo.tblOrders o
    WHERE c.CompanyID = o.CompanyID
    ORDER BY SalesOrderID DESC
    ) AS a
WHERE Type = 'End-User' 
样本结果:

CompanyID, SalesOrderID, SalesPrice, LastSalesDate, DateLast6MonthFromToday
101        10001         50          2/01/2016   10/20/2016
102        10002         80          12/01/2016  10/20/2016
103        10003         80          5/01/2016   10/20/2016
我想做的是比较LastSalesDate和DateLast6MonthFromToday。情况如下:

  • 如果LastSalesDate较小(较早),则插入到tblOrders(CompanyID,Column1,Column2…)值(CompanyIDFromQuery,Column1Value,Column2Value)
  • 否则,请更新tblOrders SET SalesPrice=1111,其中SalesOrderID=a.SalesOrderID
作为上述示例结果,查询将只更新SalesOrderID10001和10003。对于公司102,没有插入,因为LastSaleDate更大,那么只需更新SalesOrderID

我知道,如果我创建一个游标来循环每个记录并进行比较,然后进行更新或插入,这可能是可以做到的,但我想知道是否有其他方法可以在没有循环的情况下执行此操作,因为我有大约20K条记录


很抱歉造成混淆,

我不知道您的表结构和数据类型。我也什么都不知道 关于这两个表之间的重复和联接关系。 但我只想在下一个示例中展示它是如何工作的:

use [your test db];
go

create table dbo.tblCompany
(
    companyid int,
    companyname varchar(max),
    lastsaledate datetime,
    [type] varchar(max)
);

create table dbo.tblOrders 
(
    CompanyID int, 
    SalesOrderID int, 
    SalesPrice float
);


insert into dbo.tblCompany 
values
    (1, 'Avito', '2016-01-01', 'End-User'),
    (2, 'BMW', '2016-05-01', 'End-User'),
    (3, 'PornHub', '2017-01-01', 'End-User')

insert into dbo.tblOrders
values
    (1, 1, 500),
    (1, 2, 700),
    (1, 3, 900),
    (2, 1, 500),
    (2, 2, 700),
    (2, 3, 900),
    (3, 1, 500),
    (3, 2, 700),
    (3, 3, 900)

declare @column_1_value int = 5;
declare @column_2_value int = 777;

with cte as (
    select
        CompanyID,
        SalesOrderID,
        SalesPrice 
    from (
        select 
            CompanyID,
            SalesOrderID, 
            SalesPrice, 
            row_number() over(partition by CompanyID order by SalesOrderId desc) as rn
        from 
            dbo.tblOrders
    ) t
    where rn = 1
)

merge cte as target 
using (select * from dbo.tblCompany where [type] = 'End-User')  as source
    on target.companyid = source.companyid
    and source.lastsaledate >= dateadd(month, -6, getdate())
when matched 
    then update set target.salesprice = 1111
when not matched
    then insert (
        CompanyID,
        SalesOrderID,
        SalesPrice
    )
    values (
        source.CompanyId,
        @column_1_value,
        @column_2_value
    );

select * from dbo.tblOrders

如果您能给我一个信息,那么我可以正确地准备目标表和源表。

您至少应该显示表的架构,并告诉我们如何连接它们。我不理解这里的问题。为什么不能只执行insert和update语句保存示例表数据..使用merge语句。如果只想定义一次逻辑,那么可以使用
merge
语句来完成,但它会变得非常庞大。如果不介意定义两次逻辑,那么可以使用单独的
insert
update
语句。中间点是基于该语句创建一个视图,然后在单独的
insert
update
语句中使用该视图。选项很多,没有答案;)。您希望创建一个视图还是创建一个长的
merge
语句?目前是如何运行的?通常,您会将所有这些都打包到一个存储过程中。非常感谢您提供的示例代码。对我来说这看起来很复杂,但我会尽力让你知道。你的解决方案是完美的。我跟踪了你的样品,了解了它的工作原理。然后将这种逻辑应用到我的情况中,效果很好。如果没有示例代码,我将无法理解这一点。再次感谢。@Milacay在任何情况下都请小心,因为在合并语句中,您不能更新一行两次。我明白了。再次感谢!