Update table set column = case when there is a duplicate found - sql

I want to update a column in a table that would set to plus 1 if it can find a duplicate number in the column cownnum and else it would set to 1 if no duplicate was found
I tried the code below but show error
Msg 512, Level 16, State 1, Line 53
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
The statement has been terminated.
update dbo.temp1 set SEQNO = case SEQNO when (SELECT
cownnum
FROM
dbo.temp1
GROUP BY
cownnum
HAVING
COUNT(*) > 1) then SEQNO = 2 else SEQNO = 1 end
for example the result would be
cownnum 1 1 2 3
SEQNO 1 2 1 1

Your question is confusing, but there's no reason to use the GROUP BY clause:
UPDATE dbo.temp1 SET SEQNO = 1 WHERE SEQNO = cownnum
or perhaps you need to check cownnum somehow:
UPDATE dbo.temp1 SET SEQNO = 1 WHERE cownnum = (SELECT TOP 1 xxx FROM table WHERE ???)
Please provide an example of your data and the expected results.

You can use ROW_NUMBER.
UPDATE t1
SET t1.SEQNO = t2.rowno
FROM table_with_duplicates t1
INNER JOIN
(
SELECT unique_id,
ROW_NUMBER() OVER (PARTITION BY cownnum ORDER BY cownnum) AS rowno
FROM table_with_duplicates
) t2
ON t1.unique_id = t2.unique_id;

The perfect solution for your requirement is
UPDATE #Temp1
SET SEQNO = B.NewSEQ
FROM #Temp1 A ,
( SELECT id,
CASE WHEN COWNNUM = LAG(COWNNUM) OVER ( ORDER BY id ) THEN
ROW_NUMBER() OVER ( PARTITION BY COWNNUM ORDER BY id ) ELSE 1 END AS NewSEQ
FROM #temp1
) B
WHERE A.id = B.id
you can check this query execution by clicking on DEMO

You can use lag() to check previous row value in sqlserver
Update temp1
set temp1.SEQNO = B.SEQNO
FROM temp1 A, (select id , COWNNUM,
case when COWNNUM = lag(COWNNUM) over(order by id)
then ROW_NUMBER() OVER ( PARTITION BY COWNNUM ORDER BY id ) else 1 end as SEQNO
from temp1) B
WHERE A.id = B.id
DEMO

You can use window functions. This is simplest using an updatable CTE:
with toupdate as (
select t.*,
row_number() over (partition by cownum order by (select null)) as new_seqno
from dbo.temp1 t
)
update toupdate
set seqno = new_seqno;
If I understand the question correctly, no join is required.

Related

SQL get entries where on attribute is max

I have the following dataset:
id
id_rev
time
1
1
08.01.2022
1
0
31.02.2021
2
2
28.01.2017
2
1
25.07.2021
2
0
25.07.2021
I am looking for a SQL query that can return an entry per id but only the one where the id_rev is maximum. So in this case it should return these two rows:
(id=1, id_rev=1,time)
(id=2, id_rev=2, time)
One canonical approach uses ROW_NUMBER:
WITH cte AS (
SELECT t.*, ROW_NUMBER() OVER (PARTITION BY id ORDER BY id_rev DESC) rn
FROM yourTable t
)
SELECT id, id_rev, time
FROM cte
WHERE rn = 1
ORDER BY id;
Another approach would be to use exists logic:
SELECT id, id_rev, time
FROM yourTable t1
WHERE NOT EXISTS (
SELECT 1
FROM yourTable t2
WHERE t2.id = t1.id AND t2.id_rev > t1.id_rev
);
#result =
SELECT
*,
RANK()
OVER (PARTITION BY id ORDER BY id_rev DESC) AS Rank
FROM dataset ORDER BY Rank;
#result =
SELECT *
FROM #result
WHERE Rank = 1;

Get MAX ID from multiple records in table where ID2 is the same and where Value 3<>0

In the above screenshot I need to get the subplanid where MAX(ID) in that group of subplanid does not have a formularymixtype of 0
I think this does what you want:
select t.*
from (select t.*,
row_number() over (partition by subplanid order by id desc) as seqnum
from t
) t
where seqnum = 1 and formularymixtype <> 0;
This query will query out subplainid from table where will take last id and formularymixtype is not equal to 0
SELECT subplainid FROM table t
where id = (select max(id) from table where formularymixtype <> 0 )

SQL Joining table with Min and Sec Min row

I want to join table 1 with table2 twice becuase I need to get the first minimum record and the second minimum. However, I can only think of using a cte to get the second minimum record. Is there a better way to do it?
Here is the table table:
I want to join Member with output table FirstRunID whose Output value is 1 and second RunID whose Output value is 0
current code I am using:
select memid, a.runid as aRunid,b.runid as bRunid
into #temp
from FirstTable m inner join
(select min(RunID), MemID [SecondTable] where ouput=1 group by memid)a on m.memid=a.memid
inner join (select RunID, MemID [SecondTable] where ouput=0 )b on m.memid=a.memid and b.runid>a.runid
with cte as
(
select row_number() over(partition by memid, arunid order by brunid ),* from #temp
)
select * from cte where n=1
You can use outer apply operator for this:
select * from t1
outer apply(select top 1 t2.runid from t2
where t1.memid = t2.memid and t2.output = 1 order by t2.runid) as oa1
outer apply(select top 1 t2.runid from t2
where t1.memid = t2.memid and t2.output = 0 order by t2.runid) as oa2
You can do this with conditional aggregation. Based on your results, you don't need the first table:
select t2.memid,
max(case when output = 1 and seqnum = 1 then runid end) as OutputValue1,
max(case when output = 0 and seqnum = 2 then runid end) as OutputValue2
from (select t2.*,
row_number() over (partition by memid, output order by runid) a seqnum
from t2
) t2
group by t2.memid;
declare #FirstTable table
(memid int, name varchar(20))
insert into #firsttable
values
(1,'John'),
(2,'Victor')
declare #secondtable table
(runid int,memid int,output int)
insert into #secondtable
values
(1,1,0),(1,2,1),(2,1,1),(2,2,1),(3,1,1),(3,2,0),(4,1,0),(4,2,0)
;with cte as
(
SELECT *, row_number() over (partition by memid order by runid) seq --sequence
FROM #SECONDTABLE T
where t.output = 1
union all
SELECT *, row_number() over (partition by memid order by runid) seq --sequence
FROM #SECONDTABLE T
where t.output = 0 and
t.runid > (select min(x.runid) from #secondtable x where x.memid = t.memid and x.output = 1 group by x.memid) --lose any O output record where there is no prior 1 output record
)
select cte1.memid,cte1.runid,cte2.runid from cte cte1
join cte cte2 on cte2.memid = cte1.memid and cte2.seq = cte1.seq
where cte1.seq = 1 --remove this test if you want matched pairs
and cte1.output = 1 and cte2.output = 0

SQL Or with a stop after first check

Is it possible to have SQL stop checking the WHERE clause once a condition is met? For instance, if I have a statement as below:
SELECT * FROM Table1
WHERE Table1.SubID = (SELECT TOP 1 SubID FROM Table2 ORDER BY Date DESC)
OR Table1.OrderID = (SELECT TOP 1 OrderID FROM Table2 ORDER BY Date DESC)
Is it possible to stop execution after the first check? In essence, only one of the two checks in the where clause should be used, giving precedence to the first. Example cases below.
Example Cases:
Case1
Table1 SubID=600 OrderID=5
Table2 TOP 1 SubID=NULL
Table2 TOP 1 OrderID=5
Matches the OrderID to 5
Case 2
Table1 SubId=600 OrderId=5
Table2 Top 1 SubID=600
Table2 Top 1 OrderID=3
Matches to SubID=600, not OrderID=3
Given suggested answers, a with seems the best possible solution to solve what SQL is not inherently able to do. For my specific situation, the issue comes when attempting to put this into an outer apply, as below.
SELECT * FROM tbl_MainFields
OUTER APPLY
(
WITH conditional AS
(
SELECT 1 AS 'choice', PlanCode, Carrier
FROM tbl_payers
WHERE tbl_payers.PlanCode =
(
SELECT TOP 1 PlanCode
FROM tbl_payerDenials
WHERE tbl_payerDenials.AccountNumber = tbl_mainFields.AccountNumber
ORDER BY InsertDate DESC
)
UNION ALL
SELECT 2 AS 'choice', PlanCode, Carrier
FROM tbl_payers
WHERE tbl_payers.OrderNum =
(
SELECT TOP 1 DenialLevel
FROM tbl_payerDenials
WHERE tbl_payerDenials.AccountNumber = tbl_mainFields.AccountNumber
ORDER BY InsertDate DESC
)
)
SELECT
PlanCode AS DenialPC,
Carrier AS DenialCAR
FROM conditional
WHERE choice = (SELECT MIN(choice) FROM conditional)
) denialData
I think you can try something like this
WITH conditional AS(
SELECT 1 AS 'choice', PlanCode, Carrier
FROM tbl_payers
WHERE tbl_payers.PlanCode =
(
SELECT TOP 1 PlanCode
FROM tbl_payerDenials
JOIN tbl_mainFields ON
tbl_payerDenials.AccountNumber = tbl_mainFields.AccountNumber
ORDER BY InsertDate DESC
)
UNION ALL
SELECT 2 AS 'choice', PlanCode, Carrier
FROM tbl_payers
WHERE tbl_payers.OrderNum =
(
SELECT TOP 1 DenialLevel
FROM tbl_payerDenials
JOIN tbl_mainFields ON
tbl_payerDenials.AccountNumber = tbl_mainFields.AccountNumber
ORDER BY InsertDate DESC
)
)
SELECT * FROM tbl_MainFields tMF
OUTER APPLY
(
SELECT *
FROM conditional c
WHERE c.choice = (SELECT MIN(choice) FROM conditional)
) denialData
I'm using the 1 and 2 values to mark the queries, and then select the information from the first, if it returns values, otherwise it returns values from the second query (the MIN(choice) part).
I hope it is clear.
No, this cannot be done. The query optimizer, when sent a query, optimizes the entire query. Further, it creates a plan to leverage the entire query. If you need to do this you'll want to look at doing something like this:
SELECT *
INTO #tbl
FROM Table1
WHERE Table1.SubID = (SELECT TOP 1 SubID FROM Table2 ORDER BY Date DESC)
IF ( NOT EXISTS (SELECT * FROM #tbl) )
BEGIN
SELECT *
INTO #tbl
FROM Table1
WHERE Table1.OrderID = (SELECT TOP 1 OrderID FROM Table2 ORDER BY Date DESC)
END
Credit to #RaduGheorghiu for the inspiration.
This functionality is similar to the WITH and MIN combination suggested, but allows for use within an OUTER APPLY
SELECT * FROM tbl_MainFields
OUTER APPLY
(
SELECT TOP 1
PlanCode AS DenialPC,
Carrier AS DenialCAR,
Precedence
FROM
(
SELECT
1 AS 'Precedence',
PlanCode,
Carrier
FROM tbl_payers
WHERE tbl_payers.PlanCode =
(
SELECT TOP 1 PlanCode
FROM tbl_payerDenials
WHERE tbl_payerDenials.AccountNumber = tbl_mainFields.AccountNumber
ORDER BY InsertDate DESC
)
UNION ALL
SELECT
2 AS 'Precedence',
PlanCode,
Carrier
FROM tbl_payers
WHERE tbl_payers.OrderNum =
(
SELECT TOP 1 DenialLevel
FROM tbl_payerDenials
WHERE tbl_payerDenials.AccountNumber = tbl_mainFields.AccountNumber
ORDER BY InsertDate DESC
)
) AS denialPrecedence
ORDER BY Precedence
) denialData

Updating a column with the earliest date which has the same identifier, and has a column > 0

I have a database which, simiplified, is as follows :
ID | SecondID | DateRecorded | NumberToCheck | NumberToUpdate
NumberToUpdate currently has a value for 0 for all rows.
I wish to update NumberToUpdate with the value for NumberToCheck on the same row, MINUS the value for NumberToCheck which has the earliest DateRecorded "(Min(DateRecorded)" where NumberToCheck is greater than 0, and which has the same ID and secondID as the original row.
So far I have
UPDATE dbo.Table
SET NumberToUpdate =//Update NumberToUpdate
NumberToCheck - //NumberToCheck from the current row, subtracting...
(SELECT TOP 1 t2.NumberToCheck FROM Table t2 WHERE ID = t2.ID AND secondID = t2.secondID AND t2.DateRecorded =
(SELECT TOP 1 MIN(t3.DateRecorded) FROM Table t3 WHERE t2.ID = t3.ID AND t2.secondID = t3.secondID AND t3.Passes > 0))
//the NumberToCheck with the earliest date, of the same ID.
This is not correct however, and is returning me values which make no sense (including minus values of which there shouldn't be any!)
What have I forgotten here?
Thanks very much
First, you should start with a select query to get the value you want:
select t.*
from (select t.*, row_number() over (partition by id order by date) as seqnum
from table t
where number_to_check > 0
) t
where seqnum = 1
Now, you can use this in your original update:
with vals as (select t.*
from (select t.*, row_number() over (partition by id order by date) as seqnum
from table t
where NumberToCheck > 0
) t
where seqnum = 1
)
update table
set NumberToUpdate = NumberToCheck - vals.NumberToCheck
from vals
where t.id = vals.id
UPDATE dbo.Table as t1
INNER JOIN
(
SELECT MIN(DateRecord) as mindate, ID
FROM dbo.Table
GROUP BY ID
) as mindates
ON t1.ID = mindates.ID
INNER JOIN
dbo.Table as substractions
ON mindates.mindate = substraction.DateRecord
AND mindates.ID = substraction.ID
SET t1.numberToUpdate = t1.numberToCheck - substractions.NumberToCheck
WHERE substraction.NumberToCheck > 0
--your questions is ambigious here: did you mean this one should be greater than 0, or should t1.NumberToCheck > 0 ?
AND t1.DateRecord <> mindates.mindate
--Assuming that you don't want to update the record with the lowest date.
Note:
This assumes that DateRecord combined with ID is unique, which isn't guaranteed by your structure. I'm afraid that with this table layout, there is no other way.