多行合并多行

时间:2015-06-29 00:41:15

标签: sql sql-server merge

我想要一次性完成的更新是将数据插入到与一个表上的主键匹配的2个表中,将secondaryID插入另一个表上。初始数据的集合将具有多个具有相同secondaryID的行。我想要大部分最新数据。如果可以添加它以允许我同时执行更新功能,那将是非常棒的。

USE [TestDB]
GO

--DELETING CREATED FUNCTIONS, TABLES, AND TYPES
IF EXISTS (SELECT 1 FROM sys.procedures WHERE name = 'sp_Proc_1' AND [TYPE] IN (N'P',N'PC'))
  BEGIN
      DROP PROCEDURE dbo.sp_Proc_1;
  END

IF EXISTS (SELECT 1 FROM sys.types WHERE is_user_defined = 1 AND is_table_type = 1 AND name = 'My_Table_Type_1')
    BEGIN
        DROP TYPE dbo.My_Table_Type_1;
    END

IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'dbo' AND TABLE_NAME = 'Table_Data'))
BEGIN
    DROP TABLE Table_Data;
END

IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'dbo' AND TABLE_NAME = 'Table_1'))
BEGIN
    DROP TABLE Table_1;
END

IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'dbo' AND TABLE_NAME = 'Table_2'))
BEGIN
    DROP TABLE Table_2;
END

/****** Object:  Table [dbo].[Table_1]    Script Date: 6/28/2015 6:15:00 PM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO
--CREATE SAMPLE TABLE WITH DATA
CREATE TABLE [dbo].[Table_Data](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [secondaryID] [varchar](50) NULL,
    [col1] [varchar](50) NULL,
    [col2] [varchar](50) NULL,
    [col3] [int] NULL
 CONSTRAINT [PK_Table_Data] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

INSERT INTO Table_Data (secondaryID,col1,col2,col3) VALUES ('1234','Mickey','Magic Kingdom',1);
INSERT INTO Table_Data (secondaryID,col1,col2,col3) VALUES ('1234','Goofy','Epcot',1);
INSERT INTO Table_Data (secondaryID,col1,col2,col3) VALUES ('1234','Minnie','Disney',2);
INSERT INTO Table_Data (secondaryID,col1,col2,col3) VALUES ('5678','Toy Story','Universal Studios',4);
INSERT INTO Table_Data (secondaryID,col1,col2,col3) VALUES ('5678','Willie','Sea World',5);

--FIRST TABLE FOR DATA TO BE COPIED INTO BY ID
CREATE TABLE [dbo].Table_1(
    [id] [int] NULL,
    [secondaryID] [varchar](50) NULL,
    [col1] [varchar](50) NULL,
    [col2] [varchar](50) NULL,
    [col3] [int] NULL
) ON [PRIMARY]
GO

--SECOND TABLE THAT HAS SECONDARY ID AS "UNIQUE ID"
CREATE TABLE [dbo].Table_2(
    [secondaryID] [varchar](50) NULL,
    [col1] [varchar](50) NULL,
    [col2] [varchar](50) NULL,
    [col3] [int] NULL
) ON [PRIMARY]
GO

--CREATE TABLE TYPE (FOR APPLICATION)
CREATE TYPE dbo.My_Table_Type_1 AS TABLE(
    [id] [int] NULL,
    [secondaryID] [varchar](50) NULL,
    [col1] [varchar](50) NULL,
    [col2] [varchar](50) NULL,
    [col3] [int] NULL
)
GO

--CREATE STORED PROCEDURE FOR MULTI MERGE AND MULTI ROW (UPDATE ELSE INSERT)
CREATE PROCEDURE dbo.sp_Proc_1
@myTBL dbo.My_Table_Type_1 READONLY
AS
BEGIN
    DECLARE @myTBL2 dbo.My_Table_Type_1;
    INSERT INTO @myTBL2
    SELECT * FROM @myTBL;

    MERGE dbo.Table_1 AS Target
    USING @myTBL AS Source
    ON Target.ID = Source.ID
    WHEN MATCHED THEN
        UPDATE SET 
        Target.secondaryID = Source.secondaryID,
        Target.col1 = Source.col1,
        Target.col2 = Source.col2,
        Target.col3 = Source.col3
    WHEN NOT MATCHED THEN
        INSERT
        (id,secondaryID,col1,col2,col3) 
        VALUES
        (Source.id,Source.secondaryID,Source.col1,Source.col2,Source.col3);  

    MERGE dbo.Table_2 AS Target
    --gets latest data
    USING(SELECT * FROM (SELECT *, SUM(col3) OVER(PARTITION BY secondaryID) sumcol3, ROW_NUMBER() OVER(PARTITION BY secondaryID ORDER BY id DESC) rn FROM @myTBL)t WHERE rn = 1) AS Source
    --USING @myTBL AS Source
    ON Target.secondaryID = Source.secondaryID
    WHEN MATCHED THEN
        UPDATE SET
        Target.col1 = Source.col1,
        Target.col2 = Source.col2,
        --Target.col3 = Target.col3 + Source.col3
        Target.col3 = sumcol3
        --Target.col3 = 7 --<---------------THIS DOES NOT GET SAVED
    WHEN NOT MATCHED THEN
        INSERT
        (secondaryID,col1,col2,col3)
        VALUES
        (Source.secondaryID,Source.col1,Source.col2,Source.col3);
END
GO

SET ANSI_PADDING OFF
GO

--GET DATA AND EXECUTE PROC (SIMULATE APPLICATION)
DECLARE @tbl My_Table_Type_1

INSERT INTO @tbl
SELECT * FROM Table_Data;

EXECUTE sp_Proc_1 @myTBL = @tbl

--FIRST SELECT IS CORRECT, should list every value
SELECT * FROM Table_1;

--SECOND SELECT IS ***NOT*** CORRECT
SELECT * FROM Table_2;
--I WANT THIS DATA TO SHOW 2 ITEMS
--  1234    Minnie  Disney      4
--  5678    Willie  Sea World   9

1 个答案:

答案 0 :(得分:2)

我认为您可以使用typedef struct {int a;} age; typedef struct {int h;} height; void printPerson(age a, height h) { printf("Age %d, height %d\n", a.a, h.h); } age a = {30}; height h = {180}; printPerson(h, a); // will generate errors window语句using部分中的merge函数来完成此操作:

MERGE dbo.Table_2 AS Target
USING(SELECT * FROM (SELECT *, 
                            SUM(col3) OVER(PARTITION BY secondaryID) sumcol3,
                            ROW_NUMBER() OVER(PARTITION BY secondaryID ORDER BY id DESC) rn
                      FROM @myTBL)t WHERE rn = 1) AS Source
....
UPDATE SET
    Target.col1 = Source.col1,
    Target.col2 = Source.col2,
    Target.col3 = Source.sumcol3
...
WHEN NOT MATCHED THEN
    INSERT
    (secondaryID,col1,col2,col3)
    VALUES
    (Source.secondaryID, Source.col1, Source.col2, Source.sumcol3);