Skip to Main Content

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, David21.

Asked: August 15, 2016 - 5:40 pm UTC

Last updated: August 18, 2016 - 8:37 am UTC

Version: Oracle DB 11G

Viewed 1000+ times

You Asked

I have a table for Vehicle owners as follows. The table has 3 columns, Customer id, Vehicle Identification number, and whether the customer is a Primary or Secondary driver on the vehicle.

Customer_ID, Vehicle_VIN, Relationship
0001, 12345678, PRI
0001, 23456789, SEC
0001, 12345678, SEC
0002, 23456789, PRI
0002, 12345678, SEC


A customer can either be Primary (PRI) or Secondary (SEC) on a vehicle but not both. However the table has some erroneous data such that some customers are listed as Primary and secondary on the same vehicle.

I need to write a query such that If a customer is listed as primary and secondary on a vehicle, the query should only return only the Primary row.

For example, when executed on the above data the query should return the following:

Customer_ID, Vehicle_VIN, Relationship
0001, 12345678, PRI
0001, 23456789, SEC
0002, 23456789, PRI
0002, 12345678, SEC

Thanks,
Dave

and Connor said...

I'm taking advantage of the fact that "PRI" sorts before "SEC", but you might want to code that sort order explicitly. Anyway...

SQL> create table c ( cust varchar2(10), vin int, tag varchar2(10));

Table created.

SQL>
SQL> insert into c values ('0001', 12345678, 'PRI');

1 row created.

SQL> insert into c values ('0001', 23456789, 'SEC');

1 row created.

SQL> insert into c values ('0001', 12345678, 'SEC');

1 row created.

SQL> insert into c values ('0002', 23456789, 'PRI');

1 row created.

SQL> insert into c values ('0002', 12345678, 'SEC');

1 row created.

SQL>
SQL> select * from c;

CUST              VIN TAG
---------- ---------- ----------
0001         12345678 PRI
0001         23456789 SEC
0001         12345678 SEC
0002         23456789 PRI
0002         12345678 SEC

5 rows selected.

SQL>
SQL> select c.* ,
  2         row_number() over ( partition by cust,vin order by tag ) as seq
  3  from   c;

CUST              VIN TAG               SEQ
---------- ---------- ---------- ----------
0001         12345678 PRI                 1
0001         12345678 SEC                 2
0001         23456789 SEC                 1
0002         12345678 SEC                 1
0002         23456789 PRI                 1

5 rows selected.

SQL>
SQL> select *
  2  from
  3    ( select c.* ,
  4             row_number() over ( partition by cust,vin order by tag ) as seq
  5      from   c
  6    )
  7  where seq = 1;

CUST              VIN TAG               SEQ
---------- ---------- ---------- ----------
0001         12345678 PRI                 1
0001         23456789 SEC                 1
0002         12345678 SEC                 1
0002         23456789 PRI                 1

4 rows selected.

SQL>
SQL>


Hope this helps.

Rating

  (5 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

A shorter version

Mike, August 16, 2016 - 11:56 am UTC

Why not
select customer_id, vehicle_vin, min(relationship)
from c
group by customer_id, vehicle_vin;
Connor McDonald
August 17, 2016 - 1:15 am UTC

Nice input.

I working under the assumption there are more columns to obtain.

Other Variations

Rajeshwaran, Jeyabal, August 17, 2016 - 11:19 am UTC

demo@ORA11G> select cust,vin,
  2    max(tag) keep(dense_rank first order by
  3              case when tag ='PRI' then 1 end nulls last) tag
  4  from c
  5  group by cust,vin
  6  order by cust,vin ;

CUST              VIN TAG
---------- ---------- ----------
0001         12345678 PRI
0001         23456789 SEC
0002         12345678 SEC
0002         23456789 PRI

4 rows selected.

demo@ORA11G>

Chris Saxon
August 17, 2016 - 12:13 pm UTC

Nice. Seems overly convoluted given the requirement though!

Chris.

Where's the constraint?

Toon Koppelaars, August 18, 2016 - 8:16 am UTC

My first thought was: "well a SQL assertion could have avoided that erroneous data", but then I quickly realized that there's just a key missing on that table.

A unique key on (CUSTOMER_ID,VEHICLE_VIN) would seem appropriate on that table...
Chris Saxon
August 18, 2016 - 8:37 am UTC

Indeed. That was my thought too!

Chris

To Toon Koppelaars on "SQL assertion"

Rajeshwaran, Jeyabal, August 18, 2016 - 10:05 am UTC

"well a SQL assertion could have avoided that erroneous data"

Toon - I hope we have reached enough votes for SQL Assertion - I hope this will be there in next release.

https://community.oracle.com/ideas/13028


Never enough... ;-)

Toon Koppelaars, August 18, 2016 - 12:33 pm UTC

... reached enough votes for SQL Assertion ...

We have a very impressive number of up-votes, indeed. But I always welcome more ;-)

The race hasn't been run yet, and Oracle13 is going to take while.

More to Explore

Analytics

Analytic SQL got you confused? Check out Connor McDonald's complete video course.