简体   繁体   中英

INSERT or UPDATE the table from SELECT in sql server

I have a requirement where I have to check if the record for the business date already exists in the table then I need to update the values for that business date from the select statement otherwise I have to insert for that business date from the select statement. Below is my full query where I am only inserting at the moment:

    INSERT INTO 
         gstl_calculated_daily_fee(business_date,fee_type,fee_total,range_id,total_band_count) 
     select
    @tlf_business_date,
    'FEE_LOCAL_CARD',
     SUM(C.settlement_fees),
     C.range_id,
     Count(1)
From
(
    select
        *
    from
        (
            select
                rowNumber = @previous_mada_switch_fee_volume_based_count + (ROW_NUMBER() OVER(PARTITION BY DATEPART(MONTH, x_datetime) ORDER BY x_datetime)),
                tt.x_datetime
            from gstl_trans_temp tt where (message_type_mapping = '0220') and card_type ='GEIDP1' and response_code IN('00','10','11')  and tran_amount_req >= 5000 AND merchant_type NOT IN(5542,5541,4829)
         
        ) A

        CROSS APPLY
            (
                select
                     rtt.settlement_fees,
                     rtt.range_id
                     From gstl_mada_local_switch_fee_volume_based rtt
                    where A.rowNumber >= rtt.range_start
                        AND (A.rowNumber <= rtt.range_end OR rtt.range_end IS NULL)
            ) B 
) C
group by CAST(C.x_datetime AS DATE),C.range_id

I have tried to use the if exists but could not fit in the above full query.

if exists (select 
                business_date  
          from gstl_calculated_daily_fee 
          where 
          business_date = @tlf_business_date)



UPDATE gstl_calculated_daily_fee
    SET fee_total = @total_mada_local_switch_fee_low
    WHERE fee_type = 'FEE_LOCAL_CARD' 
    AND business_date = @tlf_business_date 

    else

     INSERT INTO 
         

Please help.

You need a MERGE statement with a join.

Basically, our issue with MERGE is going to be that we only want to merge against a subset of the target table. To do this, we pre-filter the table as a CTE. We can also put the source table as a CTE.

Be very careful when you write MERGE when using a CTE. You must make sure you fully filter the target within the CTE to what rows you want to merge against, and then match the rows using ON

;with source as (
    select
        business_date = @tlf_business_date,
        fee_total = SUM(C.settlement_fees),
        C.range_id,
        total_band_count = Count(1)
    From
    (
            select
                rowNumber = @previous_mada_switch_fee_volume_based_count + (ROW_NUMBER() OVER(PARTITION BY DATEPART(MONTH, x_datetime) ORDER BY x_datetime)),
                tt.x_datetime
            from gstl_trans_temp tt where (message_type_mapping = '0220') and card_type ='GEIDP1' and response_code IN('00','10','11')  and tran_amount_req >= 5000 AND merchant_type NOT IN(5542,5541,4829)
         
    ) A

    CROSS APPLY
    (
            select
                 rtt.settlement_fees,
                 rtt.range_id
            From gstl_mada_local_switch_fee_volume_based rtt
            where A.rowNumber >= rtt.range_start
                AND (A.rowNumber <= rtt.range_end OR rtt.range_end IS NULL)
    ) B 
    group by CAST(A.x_datetime AS DATE), B.range_id
),

target as (
    select 
        business_date,fee_type,fee_total,range_id,total_band_count
    from gstl_calculated_daily_fee 
    where business_date = @tlf_business_date AND fee_type = 'FEE_LOCAL_CARD'
)

MERGE INTO target t
USING source s
ON t.business_date = s.business_date AND t.range_id = s.range_id

WHEN NOT MATCHED BY TARGET THEN INSERT
    (business_date,fee_type,fee_total,range_id,total_band_count) 
    VALUES
    (s.business_date,'FEE_LOCAL_CARD', s.fee_total, s.range_id, s.total_band_count)

WHEN MATCHED THEN UPDATE SET
    fee_total = @total_mada_local_switch_fee_low
;

The way a MERGE statement works, is that it basically does a FULL JOIN between the source and target tables, using the ON clause to match. It then applies various conditions to the resulting join and executes statements based on them.

There are three possible conditions you can do:
WHEN MATCHED THEN
WHEN NOT MATCHED [BY TARGET] THEN
WHEN NOT MATCHED BY SOURCE THEN
And three possible statements, all of which refer to the target table: UPDATE , INSERT , DELETE (not all are applicable in all cases obviously).

A common problem is that we would only want to consider a subset of a target table. There a number of possible solutions to this:

We could filter the matching inside the WHEN MATCHED clause eg WHEN MATCHED AND target.somefilter = @somefilter . This can often cause a full table scan though.

Instead, we put the filtered target table inside a CTE, and then MERGE into that. The CTE must follow Updatable View rules. We must also select all columns we wish to insert or update to. But we must make sure we are fully filtering the target, otherwise if we issue a DELETE then all rows in the target table will get deleted.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM