Update Flag Based On Change of Previous Value - sql

I have below table .Need sql ,If there is change in INPUT value then update FLAG to 1 else 0.
INPUT START_DATE PERSON_ID FLAG
42707 2017-01-01 227317 0
40000 2018-01-01 227317 1
42400 2019-01-01 227317 1
42400 2019-01-02 227317 0

You can use lag() :
select t.*,
(case when lag(input, 1, input) over (partition by person_id order by start_date) = input
then 0 else 1
end) as FLAG
from table t;

If you want this in a query, then use row_number():
select t.*,
(case when row_number() over (partition by person_id order by start_date) = 1
then 0 else 1
end) as flag
from t;
If the input_value could be the same on different rows, then use first_value():
select t.*,
(case when value <> first_value(input) over (partition by person_id order by start_date) = 1
then 0 else 1
end) as flag
from t;
Either form could be incorporated into an update using an updatable CTE if you want to update the table.
EDIT:
If you want to know if the value changes from one row to the "next", then use lag(). In an update, this looks like:
with toupdate as (
select t.*,
lag(input) over (partition by customerid order by date) as prev_input
from t
)
update toupdate
set flag = (case when prev_input <> input then 1 else 0 end);
That said, I would not advise you to store the data in the table. Instead, just put the logic in a select when you need it. Otherwise, the data could get out of date if a historical value is updated.

Related

How to filter to get one unique record using SQL

I have a table similar to this. If there is a confirmed record, I want to select the oldest record and if not, select the most recent one. In this case, I would want the 4_A record.
ID
Record
Type
Date
1_A
1
auto
4/7/2021
2_A
1
confirmed
4/1/2021
3_A
1
suggested
4/5/2021
4_A
1
confirmed
4/2/2021
5_A
1
suggested
4/5/2021
I've been able to use the a window function and QUALIFY to filter the most recent one but not sure how to include the TYPE field into the mix.
SELECT * from TABLE WHERE QUALIFY ROW_NUMBER() OVER (PARTITION BY RECORD ORDER BY RECORD,DATE DESC) = 1 ;
Let me assume that you mean the oldest confirmed date if there is a confrimed:
SELECT *
FROM TABLE
WHERE QUALIFY ROW_NUMBER() OVER (PARTITION BY RECORD
ORDER BY (CASE WHEN Type = 'Confirmed' THEN 1 ELSE 2 END),
(CASE WHEN Type = 'Confirmed' THEN DATE END) ASC,
DATE ASC
) = 1;
If you really mean the oldest date if there is a confirmed, then:
SELECT *
FROM TABLE
QUALIFY (CASE WHEN COUNT_IF( Type = 'Confirmed') OVER (PARTITION BY RECORD)
THEN ROW_NUMBER() OVER (PARTITION BY RECORD ORDER BY DATE)
THEN ROW_NUMBER() OVER (PARTITION BY RECORD ORDER BY DATE DESC)
END) = 1;

SQL create flag based on earliest/latest date

I have a data set with the following attributes:
- IDs are not unique and has multiple rows
- Each ID has a different date called 'Start Date'
I am trying to add a flag (Y/N) to determine which ID row to use, based on the earliest date.
This is what I have so far:
SELECT *,
min(Start_Date) OVER (PARTITION BY ID) AS FirstEntryFlag,
From `table`
Could someone please give me guidance on how I would achieve this? Thankyou
Is this what you want?
select (case when start_date = min(Start_Date) OVER (PARTITION BY ID)
then 1 else 0
end) as FirstEntryFlag
from t;
If the start date has duplicates for an id and you want only one row flagged, use row_number():
select (case when 1 = row_number() over (partition by id order by Start_Date)
then 1 else 0
end) as FirstEntryFlag
from t;
Finally, some databases support boolean types, so the case is not necessary. Just the conditional expression can return a valid value.

How to do Partition validation inside of partition of a table

I have a table like as below
I need to add a new column called as "FLAG" which is look like as below
The logic behind the FLAG column is
Join_date<= sys_assignment then i need to give FLAG "Y" for the minimum sys_assignment date and remaining as "N" (ex: 101 and 103 records)
If join_date> sys_assignment (if any partition satisfy this condition, in this example 102 and 104 ) consider only those records (sub partition) and give FLAG as "Y" for the maximum value of sys_assignment and remaining all are "N" (The sub partitions are highlighted in THICK colors)
Please help me on this..!!!!!
Below is for BigQuery Standard SQL
#standardSQL
SELECT empid, join_date, sys_assignment,
IF((option AND min_flag) OR (NOT option AND NOT grp AND max_flag), 'Y', 'N') flag
FROM (
SELECT *,
join_date <= sys_assignment grp,
COUNT(1) OVER(PARTITION BY empid) = COUNTIF(join_date <= sys_assignment) OVER(PARTITION BY empid) option,
sys_assignment = MIN(sys_assignment) OVER(PARTITION BY empid, join_date <= sys_assignment) min_flag,
sys_assignment = MAX(sys_assignment) OVER(PARTITION BY empid, join_date > sys_assignment) max_flag
FROM `project.dataset.table`
)
when applied to your sample data - above query produces below result (which looks to me exactly what is expected)
You can use row_number():
select t.*,
(row_number() over (partition by empid
order by (case when join_date < sys_assignment then 1 else 2 end),
(case when join_date < sys_assignment then sys_assignment end) asc,
(case when join_date < sys_assignment then NULL else sys_assignment end) desc
) = 1
) as flag
from t;
The flag here is represented as a boolean rather than as character, which is more appropriate for BigQuery.
Probably could do it with partitioning, but I find it easier to read this way.
Look if there is no record with a higher sys_assignment to get the lowest. Then look to see there is another record to No the single case.
Try this:
update mytable
set flag=case when not exists (select 'x' from mytable t where t.join_date=mytable.join_date and t.sys_assignment<mytable.sys_assignment)
and exists (select 'x' from mytable t where t.join_date=mytable.join_date and t.sys_assignment>mytable.sys_assignment)
then 'Y' else 'N' end

Eliminating duplicate records in SQL

I have a table called attribute_value with the following columns
attribute_id | start_date | value | latest_ind | mod_dtime
The latest_ind column can have a value of either 1 or 0.
I basically want to run an update script on this table which finds all the attributes that have a common start date and a latest_ind equal to one and set the latest ind to zero EXCEPT in the case where the record is the latest one.
I've managed to put together the following SELECT query but I have no idea how I would go about converting it into an update. Any pointers would be appreciated
SELECT av.attribute_id, av.start_date, count(latest_ind), max(mod_dtime)
FROM t_attribute_value av
where latest_ind = 1
group by attribute_id, start_date
having count(latest_ind) > 1
This is a case where an UPDATE using a CTE comes in handy:
;WITH ToUpdate AS (
SELECT latest_ind,
ROW_NUMBER() OVER (PARTITION BY attribute_id, start_date
ORDER BY mod_dtime DESC) AS rn
FROM attribute_value
WHERE latest_ind = 1
)
UPDATE ToUpdate
SET latest_ind = 0
WHERE rn > 1
The update operation is propagated to the real table. Hence, in case of a attribute_id, start_date partition with a population greater than one, all records but the lastest are updated.
May be something like this
Method 1 : With CTE
;WITH T AS
( SELECT attribute_id, start_date, latest_ind,
ROW_NUMBER() OVER (PARTITION BY av.attribute_id, av.start_date ORDER BY mod_dtime DESC) RN
FROM t_attribute_value
where latest_ind = 1
)
UPDATE T
SET latest_ind = 0
WHERE RN > 1
Method 2: You don't need a CTE for this
UPDATE T
SET T.latest_ind = 0
FROM t_attribute_value T
INNER JOIN
(
SELECT attribute_id, start_date, latest_ind,
ROW_NUMBER() OVER (PARTITION BY av.attribute_id, av.start_date ORDER BY mod_dtime DESC) RN
FROM t_attribute_value
where latest_ind = 1
) V
ON T.attribute_id= V.attribute_id AND V.RN > 1

SQL row_number() with conditions

I have the following information in SQL Server table:
How can I add C1-C2-C3-C4 columns? To do this each colum has different conditions. I'm using row_number() order by id_pv desc, but it doesn't work.
I think you can do this with nested case statements -- both in the partition by clause and outside the row_number(). For the first column:
select t.*,
(case when expiry_date > #somdate and
row_number() over (partition by cod_suc, cod_ramo,
(case when expiry_date > #somdate then 1 else 0 end)
order by id_pv desc) as col1
then 1 else 0
end)
from table t;
Assuming from your example you want it to place 0 when your conditions are not met, and the row number otherwise, try:
Select [your columns]
, case when ExpiryDate >= #someDate then row_number()
over (order by [list of columns])
else 0 end as c1
, case when ExpiryDate >= #someDate and Cod_grupo = 4 then row_number()
over (order by [other list of columns])
else 0 end as c2