Return Max ID SQL - sql

I have a table with several rows as mentioned below having same account id :
id account_id id_intern Name Active mobile_no landline_no email
1 0011abs 66654 A yes 098937888 098937888 a#gmail.com
2 0011abs 66655 B yes 098937666 098937666 b#gmail.com
3 0011abs 66656 C no 098937777 098937777 c#gmail.com
4 0011abs 66657 D yes 098937666 d#gmail.com
5 0011abs 66658 E yes 098937111 e#gmail.com
6 0011abs 66659 F yes 098937111 098937665
I am searching for script that can return me just one line for all the common account_id present in the table with the following condition:
For an account_id with several id_intern:
consider those lines with the status active 'yes',
then those lines with entered mobile_no (not empty),
then those lines with entered landline_no (not empty),
then those lines with entered email (not empty),
then if still we have several lines (in this case for users with name A and B)
then we will consider the line with max id_intern.
Expected Result :
id account_id id_intern Name active mobile_no landline_no email
2 0011abs 66655 B yes 098937666 098937666 b#gmail.com
I tried the script but i am unable to fulfil these conditions :(
Thanks in advance for your help.

Use row_number() window function:
select id, account_id, id_intern, Name, Active, mobile_no, landline_no, email
from (
select *, row_number() over (partition by account_id order by id_intern desc) rn
from tablename
where Active = 'yes'
and mobile_no is not null and landline_no is not null and email is not null
) t
where rn = 1
If you want 1 row for each account_id even if not all the conditions are satisfied, the you must use a conditional ORDER BY clause:
select id, account_id, id_intern, Name, Active, mobile_no, landline_no, email
from (
select *,
row_number() over (
partition by account_id
order by
case when Active = 'yes' then 1 else 2 end,
case when mobile_no is not null then 1 else 2 end,
case when landline_no is not null then 1 else 2 end,
case when email is not null then 1 else 2 end,
id_intern desc
) rn
from tablename
) t
where rn = 1

Related

One query that matches values with only one condition out of two, one query that matches values with both conditions

I'm having some sort of a blank about how to do this in SQL.
Consider this reprex in R
set.seed(123)
data.frame(ID = (sample(c(1:5), 10, replace = T)),
status = (sample(c("yes", "no"), 10, replace = T)),
amount = (sample(seq(1,50,0.01),10)))
which gives out this table
ID status amount
1 3 no 29.87
2 3 yes 26.66
3 2 yes 15.49
4 2 yes 18.89
5 3 yes 44.06
6 5 no 30.79
7 4 yes 17.13
8 1 yes 6.54
9 2 yes 45.68
10 3 yes 12.66
I need to find two SQL queries.
One where I select the ID's that only have status of 'NO'
meaning ID 5.
and
One where I select the ID's that match both conditions, meaning ID 3
I have a query for both but I'm almost sure it's not correct so any lead is more than welcome.
Thanks
One where I select the ID's that only have status of 'NO' meaning ID 5.
select id from your_table where status='no' and id not in (select id from
your_table where status='yes')
One where I select the ID's that match both conditions, meaning ID 3
select id from your_table where status='no' and id in (select id from
your_table where status='yes')
At last I think you are expecting ids which do not match these conditions. so UNION both queries and get ids of your table which not exists after UNION
select id from your_table where id not in (
select id from your_table where status='no' and id not in
(select id from your_table where status='yes')
union all
select id from your_table where status='no' and id in
(select id from your_table where status='yes')
)

How to set an incrementing flag column for related rows?

I am trying to create a flag column called "Related" to use in reporting to highlight specific rows that are related based on the ID column (1 = related, NULL = not related). The original table "table1" looks like below:
Name ID Related
--------------------------------
Jack 101 NULL
John 101 NULL
Pat 105 NULL
Ben 106 NULL
Jordan 106 NULL
George 300 NULL
Alan 500 NULL
Bill 200 NULL
Bob 200 NULL
I then used this UPDATE statement below:
UPDATE a
SET Related = 1
FROM table1 a
JOIN (SELECT ID FROM table1 GROUP BY ID HAVING COUNT(*) > 1) b
ON a.ID = b.ID
Below is the result of this update statement:
Name ID Related
--------------------------------
Jack 101 1
John 101 1
Pat 105 NULL
Ben 106 1
Jordan 106 1
George 300 NULL
Alan 500 NULL
Bill 200 1
Bob 200 1
This gets me close but I need for it to instead of assigning the number 1 to each related row, to increment the number for each set of related rows based on their different ID column values.
Desired result:
Name ID Related
--------------------------------
Jack 101 1
John 101 1
Pat 105 NULL
Ben 106 2
Jordan 106 2
George 300 NULL
Alan 500 NULL
Bill 200 3
Bob 200 3
This is a possible solution using dense_rank to number your related values and an updateable CTE
with r as (
select id
from t
group by id having Count(*) > 1
),
n as (
select t.id, t.related, Dense_Rank() over (order by r.id) r
from r
join t on t.id = r.id
)
update n set related = r
You can do this without a self-join, just using window functions in a CTE, and updating the CTE directly:
WITH tCounted AS (
SELECT
t.id,
t.related,
c = COUNT(*) OVER (PARTITION BY r.id)
FROM t
),
tWithRelated as (
SELECT
t.id,
t.related,
rn = DENSE_RANK() OVER (ORDER BY r.id)
FROM tCounted
WHERE c > 1
)
UPDATE tWithRelated
SET related = rn;
Use an updateable CTE - comments explain the logic.
with cte1 as (
select [Name], ID, Related
-- Get the count within the id partition, less 1 as specified
, count(*) over (partition by id) - 1 cnt
-- Get the row number within the id partition
, row_number() over (partition by id order by id) rn
from #Test
), cte2 as (
select [Name], ID, Related, cnt, rn
-- Add 1 *only* if the count is > 0 *and* its the first row in the id partition
, case when cnt > 0 then sum(case when cnt > 0 and rn = 1 then 1 else 0 end) over (order by id) else null end NewRelated
from cte1
)
update cte2 set Related = NewRelated;
This doesn't assume Related is already null and works for more than 2 rows for any given ID.
It does assume that one can order by the ID column - even though the data provided doesn't do that.

How i want make 3 rows of the same primary key into 1 row by checking and choose its value using case

For example here, from this table
key | status
1001 | A
1001 | D
1001 | C
the hierarchy will be C>D>A
If the the stats contain C as the value, the person status will become C in one row. It will be like this:
key | status
1001 | C
it will ignore D and A because it has value C. If it doesn't has C,then it will check for D first before A.
So, how can i do that? I dont how to make the 3 row into 1. I tried using
''' CASE WHEN STATUS IN('C')THEN 'C'
ELSE WHEN STATUS IN('D') THEN 'D'
ELSE WHEN STATUS IN('A') THEN 'A'
END AS STATUS '''
But it give error and still can't make the row into 1
You can try the below -
select key, status
from tablname
order by case when status='C' then 1 when status='D' then 2 when status='A' then 3 else 99 end
FETCH FIRST 1 ROW
You can use analytical function row_number as follows:
Select * from
(Select t.*,
Row_number() over (partition by key order by case when status = 'C' then 1
when status = 'D' then 2
when status = 'A' then 3 end) as rn
From your_table)
Where rn = 1;

Handle Duplicate Record in Oracle SQL

I have a table with records like below
NAME STATUS xml_configparamdb_id xml_configuration_id
STO INACTIVE 1 1
STO ACTIVE 1 2
BOS ACTIVE 1 3
KYC INACTIVE 1 4
KYC INACTIVE 1 5
ACC ACTIVE 1 6
ACC ACTIVE 1 7
Now result I am interested in is as follows:
NAME STATUS xml_configparamdb_id xml_configuration_id
STO ACTIVE 1 2
BOS ACTIVE 1 3
KYC INACTIVE 1 4
ACC ACTIVE 1 6
That is, I want to select data on basis of STATUS .
Condition -- If STATUS is ACTIVE for both case of same Parameter - select first coming ACTIVE
Condition -- If STATUS is INACTIVE for both case of same Parameter - select first coming INACTIVE
Condition -- If STATUS is ACTIVE & INACTIVE for same Parameter - select ACTIVE
Now I used below query to populate result like above without using PRIMARY KEY Column (xml_configuration_id)
CURSOR cCnfgTypData IS
select distinct name, description, STATUS
from stg_xml_cpdb_configuration
WHERE process_exec_num = 1
AND STATUS = 'ACTIVE'
UNION ALL
select name, description, STATUS
from stg_xml_cpdb_configuration t
where process_exec_num = 1
and STATUS = 'INACTIVE'
and not exists (select * from stg_xml_cpdb_configuration
where name = t.name
and STATUS = 'ACTIVE') order by name, description;
It's showing fine data. But when I execute using PRIMARY KEY Column (xml_configuration_id) like below it's displaying all data without satisfying condition
select distinct name, description, STATUS, xml_configparamdb_id, xml_configuration_id
from stg_xml_cpdb_configuration
WHERE process_exec_num = 1
AND STATUS = 'ACTIVE'
UNION ALL
select name, description, STATUS, xml_configparamdb_id, xml_configuration_id
from stg_xml_cpdb_configuration t
where process_exec_num = 1
and STATUS = 'INACTIVE'
and not exists (select * from stg_xml_cpdb_configuration
where name = t.name
and STATUS = 'ACTIVE') order by name, description;
Use analytic function ROW_NUMBER.
SQL> SELECT name,
2 status,
3 xml_configparamdb_id,
4 xml_configuration_id
5 FROM
6 ( SELECT t.*, row_number() over (partition BY name order by status) rn FROM t
7 )
8 WHERE rn = 1
9 ORDER BY xml_configuration_id
10 /
NAM STATUS XML_CONFIGPARAMDB_ID XML_CONFIGURATION_ID
--- -------- -------------------- --------------------
STO ACTIVE 1 2
BOS ACTIVE 1 3
KYC INACTIVE 1 4
ACC ACTIVE 1 6
SQL>

SQL: Compare rows in a same table

I'm trying to compare rows in a single table
and figure out if "addr" and "zip" under the same id are same or different.
id | addr | zip
------+----------+----------
1 | 123 | 0000
1 | 123 | 0000
1 | 123 | 0001
2 | 222 | 1000
2 | 221 | 1000
So the result should say id 1 has valid addr and invalid zip
id 2 has invalid addr and valid zip.
Any hint will be appreciated! Thank you!!
The query...
SELECT id, COUNT(DISTINCT addr), COUNT(DISTINCT zip)
FROM YOUR_TABLE
GROUP BY id
...should give the following result on your example data...
1, 1, 2
2, 2, 1
The numbers in bold greater than 1 indicate "invalid" items.
If you want to actually filter on this, you can use HAVING clause, for example:
SELECT id, COUNT(DISTINCT addr) ADDR_COUNT, COUNT(DISTINCT zip) ZIP_COUNT
FROM YOUR_TABLE
GROUP BY id
HAVING ADDR_COUNT > 1 OR ZIP_COUNT > 1
May I suggest that if you don't actually want this kind of "mismatched" data in your database, redesign your data model so duplicates cannot happen in the first place. No duplicates, no mismatches!
Group by id. Select id, COUNT(DISTINCT addr) and COUNT(DISTINCT zip) columns.
Filter the rows where the number of distinct address or zips > 1.
This will give you the ids with inconsistent duplicate data.
Example:
SELECT id, COUNT(DISTINCT addr) nAddr, COUNT(DISTINCT zip) nZip
FROM [mytable]
GROUP BY id
HAVING nAddr > 1 OR nZip > 1
Cheers,
SELECT id
, CASE s.addrcount
WHEN 1 THEN 'valid'
ELSE 'invalid' END as addrok
, CASE s.zipcount
WHEN 1 THEN 'valid'
ELSE 'invalid' END as zipok
FROM
(
SELECT id
, count(distinct addr) as addrcount
, count(distinct zip) as zipcount
FROM table1
GROUP BY id
) as s