How to update specific rows based on identified rows - sql

have identified specific rows based on unique id in the data. I want to update those rows one column. Trying to use update command but its not working
UPDATE L03_A_AVOX_DATA
SET PWC_Exclusion_Flag =
(CASE
WHEN (L03_A_AVOX_DATA.PWC_SEQ_AVOX IN
(SELECT PWC_SEQ_AVOX
FROM L03_A_AVOX_DATA
WHERE client_id IN
(SELECT DISTINCT client_id
FROM ( SELECT DISTINCT
client_id,
extract_type,
COUNT (*)
FROM temp
GROUP BY client_id,
extract_type
HAVING COUNT (*) = 1))
AND extract_type = '0'))
THEN
1
ELSE
L03_A_AVOX_DATA.PWC_Exclusion_Flag
END )
Can anyone help me

You should simplify this statement by trying to simulate an UPDATE with JOIN.
For more details see here:
Update statement with inner join on Oracle
This idea should work for your case too.
So those records which have counterparts in the temp table, you update them.
Those which don't have counterparts - seems you don't want to update them anyway.

You're trying to update the PWC_Exclusion_Flag to 1 if the client_id has exactly 1 record of extract_type 0 in the temp table, am I right?
Try this:
update L03_A_AVOX_DATA
set PWC_Exclusion_Flag = 1
where client_id in (
select client_id
from temp
where extract_type = '0'
group by client_id
having count(1) = 1
);
This also leaves the other records in L03_A_AVOX_DATA untouched.

Related

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 e.g. 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.

Update Query using a Subquery to mark Duplicates

I have a Table that regularly gets Duplicate values added in. A simple fix would be to just add an extra column for me to check which has duplicates and remove accordingly. My Subquery Select statement works on its own, but not when I'm placing it as part of the Update Statement. I am using SSMS v18.7.1 and utilizing the latest SQL DB engine (I believe 2019 Express).Sample Data done with a Group By Query I understand that Update & Group By don't particularly mix well hence why I thought I could use a subquery to perform the requested action. Ideally I would also like to remove these duplicates, but there are other variables such as ApptDate & ActualDelivery Columns; However my only request is to set the Dupchecks to Yes when appropriate and then I will work on the logic for the Deletions subsequently.
Update a
Set Dupcheck = 'Yes'
from [Local DB].[dbo].[Test] a
where (
Select
ID,
count(*) as Count
From [Local DB].[dbo].[Test]
group by UID
having count(*) > 1)
You appear to be using SQL Server. I would suggest an updatable CTE:
with toupdate as
select t.*, count(*) over (partition by uid) as cnt
from [Local DB].[dbo].[Test] t
)
update toupdate
set Dupcheck = 'Yes'
where cnt > 1;
Note: If you want all but one of the rows to have the flag set, then use row_number() rather than count(*).
I think you need to use IN
Update a Set Dupcheck = Yes from [Local DB].[dbo].[Test] a where a. ID in ( Select ID From [Local DB].[dbo].[Test] group by UID having count(*) > 1)
Looking at your query it seems like you want to update all duplicate to be marked with flag as Yes.
You can use the following query to mark all the duplicates as yes:
Update test t
Set t.Dupcheck = 'Yes'
Where exists
(select 1 from Test tt
where t.uid = tt.uid
And t.id <> tt.id);
If you want to mark all except one record as duplicate then you can use > or < instead of <> in exists clause like And t.id > tt.id

MS SQL Script to find rows where value does not exist

I have a situation where I have in one table record 'a' which have order number 0 and also record 'a' but with order number 1 - this is correct.
i also have record 'b' which has order number 1 and there is no row for record 'b' where order number = 0. - this is not correct.
I need to create a script which will find all records where order number = 1 but order number 0 doesn't exist. Can you guys help with this?
i cannot use simple:
SELECT DISTINCT record FROM tablename WHERE order_number <> 0
because it will give me also record 'a' which i don't want to have in results.
I was thinking about using Not Exists function but it always compares 2 tables where i have all records in one table.
Regards
Using Not Inin Where will eliminate 'a' and will give only 'b'
Try this:-
SELECT DISTINCT record FROM tablename WHERE order_number <> 0
and record not in (Select record from tablename WHERE order_number = 0);
hope this helps:-)

SQL Server CTE - SELECT after UPDATE using OUTPUT INSERTED

I've seen a few posts on using CTE (WITH) that I thought would address my issue but I can't seem to make it work for my specific use case. My use case is that I have a table with a series of records, and I need to pull some number of records AFTER a small update has been made to them.
i.e.
- retrieve records where a series of conditions are met
- update one or more columns in each of those records
- return the updated records
I know I can return the IDs of the records using the following:
WITH cte AS
( SELECT TOP 1 * FROM msg
WHERE guid = 'abcd'
AND active = 1
ORDER BY created DESC )
UPDATE cte SET active = 0
OUTPUT INSERTED.msg_id
WHERE guid = 'abcd'
That nicely returns the msg_id field. I tried wrapping all of that in a SELECT * FROM msg WHERE msg_id IN () query, but it fails.
Anyone have a suggestion? For reference, using SQL Server 2008 R2.
CREATE TABLE #t (msg_id int)
;
WITH cte AS
( SELECT TOP 1 * FROM msg
WHERE guid = 'abcd'
AND active = 1
ORDER BY created DESC )
UPDATE cte SET active = 0
OUTPUT INSERTED.msg_id INTO #t
WHERE guid = 'abcd'
SELECT *
FROM #t
You can select the data that you need by just adding all columns that you want. INSERTED contains all columns, not just the ones written to. You can also output columns from the cte alias. Example:
OUTPUT INSERTED.SomeOtherColumn, cte.SomeOtherColumn

Updating a field based on a count of records from a different table

I need to set a value to 1 in table where the count for a given role in another table is > 1.
The table cursillo.members has fields memid and hsd. Table cursillo.teams has fields memid (the link between the two) a field called movement and another called role.
What I am trying to accomplish is something similar to this:
update cursillo.members_eligible p, cursillo.teams pp
set p.hsd=1
where p.memid = pp.memid AND (pp.role = 'HSD' OR pp.role = 'SD')
and pp.movement = 'Cursillo' AND count(pp.role) > 1;
or this:
update members_eligibile
set hsd=1
from teams
where teams.memid=members_eligible.memid
and (teams.role = 'HSD' OR teams.role = 'SD')
and teams.movement = 'Cursillo'
and count(teams.role) > 1;
In other words if a given memid has more than one record in the cursillo.teams table where the value of the role is equal to either HSD or SD, then set cursillo.members_eligible.hsd to 1.
I can't figure out to handle the count() part.
Thanks,
Mike Reed
Possible duplicate question:
MySQL - Using COUNT(*) in the WHERE clause
Try using the 'having' keyword
Here's the relevant section from the linked answer (in this case, a select statement):
select gid
from `gd`
group by gid
having count(*) > 10
order by lastupdated desc
It looks like 'having' can only be used in select statments though:
http://www.mysqltutorial.org/mysql-having.aspx
So you may need to have your update's where clause include a select statement:
update members_eligibile
set hsd=1
from teams
where teams.memid=members_eligible.memid
and (teams.role = 'HSD' OR teams.role = 'SD')
and teams.movement = 'Cursillo'
and members_eligible.memid IN
(SELECT members_eligible.memid from members_eligible where teams.memid=members_eligible.memid having count(teams.role) > 1);
You will have to adjust the select statement, I haven't tested it
SQL Server 2005+
UPDATE x
SET x.hsd = 1
FROM (SELECT e.hsd, COUNT(*) OVER (PARTITION BY t.role) AS cnt
FROM teams t JOIN members_eligibile e ON t.memid = e.memid
WHERE (t.role = 'HSD' OR t.role = 'SD') AND t.movement = 'Cursillo') x
WHERE x.cnt > 1