SQL preferred one-to-many relationship
Say I have a one-to-many relationship between clients and addresses.
Clients can have multiple addresses with different address types (eg. home, postal, wo开发者_JAVA技巧rk, company, future), and might have no address or multiple addresses of the same type (in which case I'm happy to take the 1st occurrence).
My data consists of clientid, address, and addresstypeid. The preferred order of the addresstypeid is 2,3,4,1: so if a client has an addresstypeid of 2 return that, if not return the record with 3, if not 4, if not 1 and if not null.
Is there an more elegant way to do this than something like this?
declare @addresses table
(
clientid int,
address varchar(10),
addresstypeid int
)
--2,3,4,1
insert into @addresses (clientid, address, addresstypeid)
select 1, '1a', 1 union all
select 1, '1b', 2 union all
select 1, '1c', 3 union all
select 1, '1d', 4 union all
select 2, '2a', 2 union all
select 2, '2b', 3 union all
select 2, '2c', 4 union all
select 2, '2a', 1 union all
select 3, '3a', 3 union all
select 3, '3b', 4 union all
select 3, '3c', 1 union all
select 4, '4a', 3 union all
select 4, '4b', 4 union all
select 5, '5a', 4 union all
select 6, '6a', 4 union all
select 6, '6b', 1 union all
select 7, '7a', 1 union all
select 7, '7b', 4
declare @ranktable table
(
addresstypeid int,
rank int
)
insert into @ranktable(addresstypeid, rank)
select 2, 1 union all
select 3, 2 union all
select 4, 3 union all
select 1, 4
select
e.address,
e.clientid,
e.addresstypeid
from
@addresses e
inner join @ranktable r on
e.addresstypeid = r.addresstypeid
inner join (select
em.clientid,
min(rank) minrank
from @addresses em
inner join @ranktable ranks on
em.addresstypeid = ranks.addresstypeid
group by
clientid) clientranks on
e.clientid = clientranks.clientid and
r.rank = clientranks.minrank
The two tables are fine, though you should consider indexes when you make them permanent :)
In terms of your final query, I'd change it slightly...
WITH
sorted_data
AS
(
SELECT
[a].*,
ROW_NUMBER() OVER (PARTITION BY [a].clientid ORDER BY [r].rank) AS sequence_id
FROM
@addresses AS [a]
INNER JOIN
@ranktable AS [r]
ON a.addresstypeid = r.addresstypeid
)
SELECT
*
FROM
sorted_data
WHERE
sequence_id = 1
精彩评论