Pregunta

I'm working in Microsoft SQL Server and I'm having an issue with my database where I'm trying to insert new data into a table but the data had been accidentally inserted once in the past, and as such reinserting would cause key violations. I'm looking for a way to Insert the data I need and Update what was accidentally included already. Some of the particulars of the code has been changed for brevity but my code as it stands now is:

BEGIN TRANSACTION 

INSERT INTO dbs_salesinternals.acc_saleshistory 
SELECT a, 
       b AS n 
FROM   dbs_sales.orders AS O 
       INNER JOIN dbs_salesinternals.acc_report_months AS ARM 
               ON ARM.acc_report_month_id = dbo.Reportmonth(CASE 
                             WHEN O.ordertypeid = 2 THEN shipduedate 
                             ELSE shipdate 
                                                            END) 
       INNER JOIN dbo.contactfullnames 
               ON O.customerid = dbo.contactfullnames.contact_id 
       INNER JOIN dbs_sales.ordertypes 
               ON dbs_sales.ordertypes.ordertypeid = O.ordertypeid 
       LEFT JOIN(SELECT OD.orderid, 
                        Sum(CASE 
                              WHEN PB.format LIKE '%kit%' 
                                   AND units.curriculumcode = 'CUR' THEN 
                              OD.price 
                              ELSE 0 
                            END) AS KitPart, 
                        Sum(CASE 
                              WHEN PB.format = 'PD' 
                                   AND units.curriculumcode = 'CUR' THEN 
                              OD.price 
                              ELSE 0 
                            END) AS PDPart, 
                        Sum(CASE 
                              WHEN ( PB.format <> 'PD' 
                                     AND PB.format NOT LIKE '%kit%' 
                                     AND units.curriculumcode = 'CUR' ) THEN 
                              OD.price 
                              ELSE 0 
                            END) AS OtherPart, 
                        Sum(CASE 
                              WHEN PB.format LIKE '%kit%' 
                                   AND units.curriculumcode = 'WEB' THEN 
                              OD.price 
                              ELSE 0 
                            END) AS EKitPart, 
                        Sum(CASE 
                              WHEN PB.format = 'PD' 
                                   AND units.curriculumcode = 'WEB' THEN 
                              OD.price 
                              ELSE 0 
                            END) AS EPDPart, 
                        Sum(CASE 
                              WHEN ( PB.format <> 'PD' 
                                     AND PB.format NOT LIKE '%kit%' 
                                     AND units.curriculumcode = 'WEB' ) THEN 
                              OD.price 
                              ELSE 0 
                            END) AS EGuidePart 
                 FROM   dbs_salesinternals.eieproductsbase AS PB 
                        INNER JOIN dbs_salesinternals.productpricing AS PP 
                                ON PB.productid = PP.product_id 
                        INNER JOIN dbs_sales.[order details] AS OD 
                                ON PP.productpricing_id = OD.productpricing_id 
                        INNER JOIN units 
                                ON PB.unit_id = units.unit_id 
                 GROUP  BY OD.orderid) OP 
              ON OP.orderid = O.orderid 
       LEFT JOIN [dbo].[grant_codes] 
              ON [dbo].[grant_codes].grantcodemap_id = O.accountcode 
WHERE  O.ordertotal <> 0 
       AND O.ordertypeid IN ( 1, 2, 3, 4 ) 
       AND ARM.acc_report_month_id = 166 
       AND ( [dbo].[grant_codes].granttype IS NULL 
              OR [dbo].[grant_codes].granttype <> 2 ) 

COMMIT TRANSACTION 

How can I change this to accomplish what i need?

¿Fue útil?

Solución

I haven't used the merge tool mentioned in the comments, it might be better, but here is how I would do it:

First, change your existing query into something that inserts into a temporary table (a temp-table is indicated with a #before its name):

select <your select-clause>
into #temp
from <your from-clause>
where <your where-clause>

So now we have 2 tables, both containing data. Let's call the table we are adding to S, and the temporary table to be used as a basis for the data to be added T.

First, we need to figure out which of the rows in T already exists in S. They probably have a common row identifier, let's call it id, and find the set of rows in T that have a corresponding row in S through a simple join:

select * from S s join T t on s.id = t.id;

The rows returned in this query is the rows that we want to update. To do so, a query of this type can be used:

update S 
set c1 = (select t.c1 from T t where t.id = S.id),
c2 = (select t.c2 from T t where t.id = S.id),
...
cN = (select t.cN from T t where t.id = S.id)
where S.id in (
    select t.id 
    from S s join T t on s.id = t.id);

We update all rows in S that exists in both T and S, and "pick" the values from T with inner selects.

Next, we need to insert the rows in T that are not already in S. This query will do that:

insert into S (id, c1, c2, ..., cN)
select id, c1, c2, ..., cN
from T where id not in (select id from S);

(Could have used a join in the where-clause, but this works just as well..)

This query will insert the rows in T that are not already in S into S.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top