开发者

SQL preferred one-to-many relationship

开发者 https://www.devze.com 2023-03-30 21:15 出处:网络
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 mi

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

精彩评论

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