Select row if column value not same as previous rows - sql

I have a table like below
No. FName Age Tag
1 abc 22 c
2 xyz 60 c
3 pqr 62 i
4 abc 22 i
5 abc 32 i
I want the result to be returned as
No. FName Age Tag
1 abc 22 c
2 xyz 60 c
3 pqr 62 i
5 abc 32 i
Requirement is that if a column Name AND column Age value is same for rows with tag=c and tag=i , than the tag=i row should not be selected . Row no. 1 and Row no. 4 have same values (Name,age)=(abc,22) but row 4 has tag = i.So row no 4 above (abc,22,i) has to be left out. How can I do this ?

WITH records
AS
(
SELECT No, FName, Age, Tag,
ROW_NUMBER() OVER (PARTITION BY FName, Age
ORDER BY Tag ASC) rn
FROM tableName
WHERE TAG IN ('c','i')
)
SELECT No, FName, Age, Tag
FROM records
WHERE rn = 1
SQLFiddle Demo
if you have other special values on TAG,
WITH records
AS
(
SELECT No, FName, Age, Tag,
ROW_NUMBER() OVER (PARTITION BY FName, Age
ORDER BY CASE WHEN TAG = 'c' THEN 0 ELSE 1 END ASC) rn
FROM tableName
WHERE TAG IN ('c','i')
)
SELECT No, FName, Age, Tag
FROM records
WHERE rn = 1
ORDER BY No
SQLFiddle Demo
UPDATE 1
SELECT Fname, Age, MIN(tag) Tag
FROM TableName
WHERE TAG IN ('c','i')
GROUP BY Fname, Age
SQLFiddle Demo

I think you can simply ignore all the rows with tag = 'i' if already exists row with same age, name and tag = 'c' :
select * from TableName t1
where not exists
(select 1
from TableName
where FNAme = t1.FNAme and Age = t1.Age and t1.Tag = 'i' and tag = 'c')

Related

How to append a count number in duplicate values in a column and update in SQL Server?

Currently my table looks like this; I want to add the count numbers with distinct InstanceId and duplicate values.
Id
InstanceId
Name
1
1
DiscoveryInstance
2
1
DiscoveryInstance
3
2
ETLInstance
4
3
DiscoveryInstance
5
3
DiscoveryInstance
6
2
ETLInstance
7
2
ETLInstance
I want the output to be like this:
Id
InstanceId
Name
1
1
DiscoveryInstance
2
1
DiscoveryInstance_Backup_1
3
2
ETLInstance
4
3
DiscoveryInstance
5
3
DiscoveryInstance_Backup_1
6
2
ETLInstance_Backup_1
7
2
ETLInstance_Backup_2
I don't want to update the first value and update should start with the next duplicate value in the column.
How to update this table to make this output possible in SQL Server query?
EDIT This solution addresses the ORIGINAL question and original output. This is no longer valid because you changed your desired output.
You could use rank() and concat in this manner:
with cte as (select id, name, rank() over (partition by name order by id) as name_rank
from my_table
)
select t.id,
case
when c.name_rank = 1 then t.name
else concat(t.name, '_Backup_', c.name_rank - 1)
end name
from my_table t
join cte c
on t.id = c.id
Output:
id
name
1
DiscoveryInstance
2
DiscoveryInstance_Backup_1
3
ETLInstance
4
DiscoveryInstance_Backup_2
5
DiscoveryInstance_Backup_3
6
ETLInstance_Backup_1
DB-fiddle found here. I see you updated the question after I posted this answer by adding another column, but that does not look important at the moment.
EDIT
This is an updated answer (thanks Guido) that would address your newly updated output:
with cte as (select id, name, rank() over (partition by name, instanceid order by id) as name_rank
from mytable
)
select t.id,
case
when c.name_rank = 1 then t.name
else concat(t.name, '_Backup_', c.name_rank - 1)
end name
from mytable t
join cte c
on t.id = c.id
Another option is using the row_number() like this
This solution uses your new column instanceid to get the correct data
select t.id,
case when rownumber > 1 then t.Name + '_Backup_' + convert(varchar(10), t.rownumber - 1)
else t.Name
end
from ( select t.id,
t.name,
row_number() over (partition by t.Name, t.instanceid order by t.id) as rownumber
from mytable t
) t
order by t.id
See this DBFiddle
output is
id
(No column name)
1
DiscoveryInstance
2
DiscoveryInstance_Backup_1
3
ETLInstance
4
DiscoveryInstance
5
DiscoveryInstance_Backup_1
6
ETLInstance_Backup_1
7
ETLInstance_Backup_2

sql query, order by value when field matches

I have data as follows:
data_id name value
-----------------------------------------
1 Address123 my street
1 Order-Date 12/23/2018
1 firstName Joe
2 Address 345 other street
2 Order-Date 12/31/2018
2 firstName Peter
...and so on..
How can I write a query to return the data ordered by 'OrderDate' using ID as the Group
e.g.
SELECT *
FROM wp_cf7_data_entry
WHERE cf7_id = 7
AND data_id IN (SELECT *
FROM (
SELECT data_id
FROM wp_cf7_data_entry
WHERE 1 = 1
AND cf7_id = 7
GROUP BY data_id
ORDER BY case
when name = 'order-date' THEN 'value'
end DESC,'data_id')
basically I want to use the subquery as the order by so results are sorted by Order-Date.
I'm guessing you want to use conditional aggregation:
select id,
max(case when name_field = 'OrderDate' then value end) as OrderDate,
max(case when name_field = 'Address' then value end) as Address,
max(case when name_field = 'Name' then value end) as Name
from yourtable
group by id
order by max(case when name_field = 'OrderDate' then value end)
This creates a single row for each id and orders the results by the order date value.
You dont need a group by as I can see for each id theres only one namefield as ordereddate
SELECT * FROM TABLE WHERE NAME_FIELD =
'OrderedDate' order by NAME_FIELD

Display Column Values for last record only in sql server

Hi Iam having table like below,
Name RN AGE
A 1 21
B 2 22
C 3 23
I want to display age for last record only remaining column value as empty like below,
Name RN AGE
A 1
B 2
C 3 23
Use window function
SELECT *,
(CASE WHEN MAX(AGE) OVER () = AGE THEN CAST(AGE AS VARCHAR(10)) ELSE '' END) AGE1
FROM table
You could also use CROSS JOIN
SELECT *,
(CASE WHEN t.AGE <> c.MAXAGE THEN '' ELSE CAST(t.AGE AS VARCHAR(10)) END) AGE1
FROM table t CROSS JOIN (
SELECT MAX(AGE) AS MAXAGE FROM table) c
This assumes last records in terms of AGE else you would need to RN/Name column to be aggregate and use them.

Group and tally values for each record in SQL [duplicate]

This question already has answers here:
How to use GROUP BY to concatenate strings in SQL Server?
(22 answers)
Closed 8 years ago.
Im trying to run a select statement to group records having similar IDs but also tally the values from another column for each master ID. So for example below. The result for each line will be the first instance unique ID and the 2 names shown from each record separated by semi colon. Thanks in advance.
Current set
ID Name Cnt
-------------------------------- ----------------- ---
0001D72BA5F664BE129B6AB5744E2BE0 Talati, Shilpa 1
0001D72BA5F664BE129B6AB5744E2BE0 Weaver, Larry 1
0007EAB7CE9A3F2F95D2D63D0BBD08A9 St-Hilaire, Edith 1
0007EAB7CE9A3F2F95D2D63D0BBD08A9 Talati, Shilpa 1
Result:
0001D72BA5F664BE129B6AB5744E2BE0 Talati, Shilpa; Weaver, Larry
The easiest way to solve this in SQL Server is:
select masterId, min(name) + '; ' + max(name)
from table t
group by masterId;
Here's one way using a recursive common table expression. Given a table like this:
create table dbo.Fizzbuzz
(
id int not null identity(1,1) primary key clustered ,
group_id int not null ,
name varchar(50) not null ,
cnt int not null ,
)
containing this data
id group_id name cnt
-- -------- ------ ---
1 1 Bob 3
2 1 Carol 5
3 1 Ted 6
4 1 Alice 16
5 2 Harold 72
6 2 Maude 28
This query
with recursive_cte as
(
select group_id = t.group_id ,
row = t.row ,
name = convert(varchar(8000),t.name) ,
cnt = t.cnt
from ( select * ,
row = row_number() over (
partition by group_id
order by id
)
from dbo.Fizzbuzz
) t
where t.row = 1
UNION ALL
select group_id = prv.group_id ,
row = nxt.row ,
name = convert(varchar(8000), prv.name + ' and ' + nxt.name ) ,
cnt = prv.cnt + nxt.cnt
from recursive_cte prv
join ( select * ,
row = row_number() over (
partition by group_id
order by id
)
from dbo.Fizzbuzz
) nxt on nxt.group_id = prv.group_id
and nxt.row = prv.row + 1
)
select group_id = t.group_id ,
total = t.cnt ,
names = t.name
from ( select * ,
rank = rank() over (
partition by group_id
order by row desc
)
from recursive_cte
) t
where rank = 1
order by group_id
produces the following output
group_id cnt name
-------- --- -------------------------------
1 30 Bob and Carol and Ted and Alice
2 100 Harold and Maude
One should note however, that the depth of recursion is bounded in SQL Server.
SELECT
t1.ID,
(SELECT Name + '; '
FROM yourtable t2
WHERE t1.ID = t2.ID
for xml path('')) as Name
FROM yourtable t1
GROUP BY t1.ID

Postgresql Skip Row if value is equal to last row

in Postgres 9.1 is it possible to skip row(s) if the value of NAME is equal to the one before f.e. following table
ID | NAME | AGE | SEX | CLASS
---------------------------------
1 Paul 17 M 2b
2 Paul 16 M 2b
3 Paul 18 F 2b
4 Lexi 18 M 2b
5 Sarah 16 F 2b
6 Sarah 17 F 2b
The result should be:
1 Paul 17 M 2b
4 Lexi 18 M 2b
5 Sarah 16 F 2b
Thanks for your help,
t book
select *
from (
select id,
name,
age,
sex,
class,
lag(name) over (order by id) as prev_name
from the_table
) as t
where name <> prev_name;
alternatively
select *
from (
select id,
name,
age,
sex,
class,
row_number() over (partition by name order by id) as rn
from the_table
) as t
where rn = 1;
Another option would be to use Postgres' distinct on operator:
select distinct on (name)
id,
name,
age,
sex,
class
from the_table
order by name,id
but that will return the result ordered by name (which is limitation of the distinct on operator). If you don't want that you'll need to wrap this again:
select *
from (
select distinct on (name)
id,
name,
age,
sex,
class
from the_table
order by name,id
) t
order by id;
SELECT ID , NAME , AGE , SEX , CLASS
FROM thetable t
WHERE NOT EXISTS (
SELECT * FROM thetable nx
WHERE nx.NAME = t.NAME
-- AND nx.ID < t.ID -- ANY one before it
AND nx.ID = t.ID-1 -- THE one before it
);