开发者

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜