Sql &引用;“合并”;使用文字值的样式操作?

Sql &引用;“合并”;使用文字值的样式操作?,sql,merge,sql-server-2008-r2,Sql,Merge,Sql Server 2008 R2,我有一个包含学生成绩关系的表: Student Grade StartDate EndDate 1 1 09/01/2009 NULL 2 2 09/01/2010 NULL 2 1 09/01/2009 06/15/2010 我正在尝试编写一个存储过程,该过程包含Student、Grade和StartDate,我希望 检查以确保这些值不重复 如果记录不是重复的,请插入该记录 如果存在现有

我有一个包含学生成绩关系的表:

Student   Grade   StartDate   EndDate
   1        1    09/01/2009    NULL
   2        2    09/01/2010    NULL
   2        1    09/01/2009   06/15/2010
我正在尝试编写一个存储过程,该过程包含
Student
Grade
StartDate
,我希望

  • 检查以确保这些值不重复
  • 如果记录不是重复的,请插入该记录
  • 如果存在现有的学生记录,并且该记录的
    EndDate=NULL
    ,则使用新记录的
    StartDate
    更新该记录
  • 例如,如果我调用该过程并传入
    1
    2
    09/01/2010
    ,我希望最终得到:

    Student   Grade   StartDate   EndDate
       1        2    09/01/2010    NULL
       1        1    09/01/2009   09/01/2010
       2        2    09/01/2010    NULL
       2        1    09/01/2009   06/15/2010
    

    这听起来像是我可以使用
    MERGE
    ,只是我要传递文本值,并且我需要执行多个操作。我今天早上头痛得厉害,似乎不能清晰地思考,所以我专注于这个
    MERGE
    解决方案。如果有更明显的方法可以做到这一点,不要害怕指出它。

    即使传递文字值,也可以使用
    合并。以下是您的问题的一个示例:

    CREATE PROCEDURE InsertStudentGrade(@Student INT, @Grade INT, @StartDate DATE)
    AS
    BEGIN;
    
        MERGE StudentGrade AS tbl
         USING (SELECT @Student AS Student, @Grade AS Grade, @StartDate AS StartDate) AS row
         ON tbl.Student = Row.Student AND tbl.Grade = row.Grade
        WHEN NOT MATCHED THEN
          INSERT(Student, Grade, StartDate)
           VALUES(row.Student, row.Grade, row.StartDate)
        WHEN MATCHED AND tbl.EndDate IS NULL AND tbl.StartDate != row.StartDate THEN
          UPDATE SET
            tbl.StartDate = row.StartDate;
    
    END;
    

    我更喜欢以下内容,它更干净,更容易阅读和修改

    MERGE Definition.tdSection AS Target
    USING
        (SELECT *
         FROM   ( VALUES
                ( 1, 1, 'Administrator', 1, GETDATE(), NULL, Current_User, GETDATE())
                 ,( 2, 1, 'Admissions', 1, GETDATE(), NULL, Current_User, GETDATE())
                 ,( 3, 1, 'BOM', 1, GETDATE(), NULL, Current_User, GETDATE())
                 ,( 4, 1, 'CRC', 1, GETDATE(), NULL, Current_User, GETDATE())
                 ,( 5, 1, 'ICM', 1, GETDATE(), NULL, Current_User, GETDATE())
                 ,( 6, 1, 'System', 1, GETDATE(), NULL,Current_User, GETDATE())
                 ,( 7, 1, 'Therapy', 1, GETDATE(), NULL, Current_User, GETDATE()) 
                )
                AS s (SectionId
                      ,BusinessProcessId
                      ,Description, Sequence
                      ,EffectiveStartDate
                      ,EffectiveEndDate
                      ,ModifiedBy
                      ,ModifiedDateTime)
         ) AS Source
    ON Target.SectionId = Source.SectionId
    WHEN NOT MATCHED THEN
        INSERT (SectionId
               ,BusinessProcessId
               ,Description
               ,Sequence
               ,EffectiveStartDate
               ,EffectiveEndDate
               ,ModifiedBy
               ,ModifiedDateTime
               )
        VALUES (Source.SectionId
               ,Source.BusinessProcessId
               ,Source.Description
               ,Source.Sequence
               ,Source.EffectiveStartDate
               ,Source.EffectiveEndDate
               ,Source.ModifiedBy
               ,Source.ModifiedDateTime
               );
    
    简单地说:

    --Arrange
    
    CREATE TABLE dbo.Product
    (
        Id   INT IDENTITY PRIMARY KEY,
        Name VARCHAR(40),   
    )
    GO
    
    --Act
    
    MERGE INTO dbo.Product AS Target 
    USING 
    (
        --Here is the trick :)
    
        VALUES 
            (1, N'Product A'),
            (2, N'Product B'),
            (3, N'Product C'),
            (4, N'Product D')
    ) 
    AS 
    Source 
    (
         Id,
         Name
    ) 
    
    ON Target.Id= Source.Id
    
    WHEN NOT MATCHED BY TARGET THEN 
    
    INSERT 
    (
          Name
    ) 
    VALUES 
    (
          Name
    );
    

    哦,太好了。我不知道您可以将文字值与
    合并
    一起使用!我尝试过类似的方法,但没有想到使用别名,这一点现在看起来很明显。这并不完全是我需要的,因为我需要在匹配时插入和更新,但我相信我可以在那里找到解决方案。它真正的关键是如何使用
    合并
    和我的值。多谢!你也可以这样使用:使用(VALUES(@Student,@Grade,@StartDate))作为[row](Student,Grade,StartDate)@Davos我真的很想看到你在回答中的评论。谢谢@yzorg,但我认为拉马克已经回答了这个问题的各个方面(不像下面的其他答案),我在这里的贡献很小。这并没有回答OP关于编写一个存储过程的问题,这个存储过程需要插入参数。这也忽略了问题的第3部分,即当结束日期为空时的更新。这个例子只会插入新记录,因此并不比insert语句更好。谢谢。你为我节省了很多时间。当您实际上没有两个表要合并,而是要合并文本或变量时,使用MERGE指令并利用干净的语法是一个很好的技巧。