SQL version of party:getXXXXaddress

If you are writing an SQL datasource report and you want to do the equivalent of the part:getCorrespondenceAddress() or party:getBillingAddress() functions then it is not at all obvious how to do it (or it wasn't to me).

Below are two sets of SQL that do the trick. The first is for cases where the customer id is a parameter, the second is for cases where you a dealing with multiple customers. Both rely on ranking the suitability of the contact depending on whether it is a preferred contact and its contact purpose.

If the customer id is known then (assuming you want a Correspondence address):

select e.entity_id as cid, e.name as cname, e.description as cdescription,
   addr.address as address, addr.suburb as suburb, addr.state as state,
   addr.preferred as preferred, addr.purpose as purpose, addr.rank as rank
from entities e
left join (select
        ccd1.value as address, l.name as suburb, ccd3.value as state,
        ccd4.value as preferred, lcl.code as purpose,
        if((ccd4.value = 'true'), if((lcl.code = 'CORRESPONDENCE'), 30, 10), if((lcl.code = 'CORRESPONDENCE'), 20, 0)) as rank
    from
        contacts cc
    left join contact_details ccd1 ON ccd1.contact_id = cc.contact_id
        and ccd1.name = 'address'
    left join contact_details ccd2 ON ccd2.contact_id = cc.contact_id
        and ccd2.name = 'suburb'
    left join lookups l ON l.code = ccd2.value
    left join contact_details ccd3 ON ccd3.contact_id = cc.contact_id
        and ccd3.name = 'state'
    left join contact_details ccd4 ON ccd4.contact_id = cc.contact_id
        and ccd4.name = 'preferred'
    left join contact_classifications ccl ON ccl.contact_id = cc.contact_id
    left join lookups lcl ON lcl.lookup_id = ccl.lookup_id
    where
        cc.party_id = $P{customerId}
            and cc.name = 'Location'
            and cc.active = 1
    order by if((ccd4.value = 'true'), if((lcl.code = 'CORRESPONDENCE'), 30, 10), if((lcl.code = 'CORRESPONDENCE'), 20, 0)) desc , cc.contact_id desc
    limit 1) as addr ON true
where e.entity_id = $P{customerId};

Note that the order by clause in the above is not needed (because of the 'limit 1'), but if you change the limit to say 10, then you can assure yourself of the ranking behaviour.

If you are retrieving multiple customers (assuming you want a Billing address for all customers with names starting with B:

select e.entity_id, e.name, e.description,
ccd1.value as address, l.name as suburb, ccd3.value as state,
         mx.mrank as mrank
from entities e

join contacts cc on cc.party_id = e.entity_id and cc.name = 'Location' and cc.active = 1
    left join contact_details ccd1 ON ccd1.contact_id = cc.contact_id
        and ccd1.name = 'address'
    left join contact_details ccd2 ON ccd2.contact_id = cc.contact_id
        and ccd2.name = 'suburb'
    left join lookups l ON l.code = ccd2.value
    left join contact_details ccd3 ON ccd3.contact_id = cc.contact_id
        and ccd3.name = 'state'
    left join contact_details ccd4 ON ccd4.contact_id = cc.contact_id
        and ccd4.name = 'preferred'
    left join contact_classifications ccl ON ccl.contact_id = cc.contact_id
    left join lookups lcl ON lcl.lookup_id = ccl.lookup_id
inner join (
select e1.entity_id as id,
        max(if((ccd4.value = 'true'), if((lcl.code = 'BILLING'), 30, 10), if((lcl.code = 'BILLING'), 20, 0))) as mrank
from entities e1

join contacts cc on cc.party_id = e1.entity_id and cc.name = 'Location' and cc.active = 1
    left join contact_details ccd4 ON ccd4.contact_id = cc.contact_id
        and ccd4.name = 'preferred'
    left join contact_classifications ccl ON ccl.contact_id = cc.contact_id
    left join lookups lcl ON lcl.lookup_id = ccl.lookup_id

where e1.name like 'b%'
group by e1.entity_id
) mx on e.entity_id = mx.id and mx.mrank = if((ccd4.value = 'true'), if((lcl.code = 'BILLING'), 30, 10), if((lcl.code = 'BILLING'), 20, 0))
where e.name like 'b%'
order by e.name, e.entity_id;

Hope this saves you some time.

Regards, Tim G

 

 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Re: SQL version of party:getXXXXaddress

Note that having just attempted to modify a customer sales export report as per the second method above (where you join the selection to itself) I have concluded that for complex selections with many joins, a better (and faster) approach is to have the sql return all contacts for each entity sorted by rank and contact id, and use iReports/Studio's grouping facility to display the highest ranked contact.

ie the SQL is:

select
  c.entity_id as id,
  c1.value as lastname,
  c2.value as firstname,
  l3.name as title,
  cd1.value as address,
  l2.name as suburb,
  cd3.value as postcode,
  cd4.value as state,
  max(pa.activity_start_time) as lastsale,
  if((cd5.value = 'true'), if((lcl.code = 'CORRESPONDENCE'), 30, 10), if((lcl.code = 'CORRESPONDENCE'), 20, 0)) as rank
from
  acts pa
  join act_relationships ar on pa.act_id = ar.source_id
  join acts ca on ar.target_id = ca.act_id and ca.arch_short_name like 'act.customerAccount%Item'
  join participations pp on ca.act_id = pp.act_id
  join entities pr on pr.entity_id = pp.entity_id and pr.arch_short_name like 'product.%'
  left join entity_relationships rp on rp.target_id = pr.entity_id and rp.arch_short_name = 'entityRelationship.productTypeProduct'
  left join entities pt on pt.entity_id = rp.source_id
  join participations pap on ca.act_id = pap.act_id and pap.arch_short_name = 'participation.patient'
  join entities p on p.entity_id = pap.entity_id
  join participations cp on pa.act_id = cp.act_id and cp.arch_short_name = 'participation.customer'
  join entities c on c.entity_id = cp.entity_id
  left join entity_details c1 on c1.entity_id = c.entity_id and c1.name = 'lastName'
  left join entity_details c2 on c2.entity_id = c.entity_id and c2.name = 'firstName'
  left join entity_details c3 on c3.entity_id = c.entity_id and c3.name = 'title'
  left join lookups l3 on l3.code = c3.value and l3.arch_short_name = 'lookup.personTitle'
  left join contacts cc on cc.party_id = c.entity_id and cc.arch_short_name = 'contact.location'
  left join contact_details cd1 on cd1.contact_id = cc.contact_id and cd1.name = 'address'
  left join contact_details cd2 on cd2.contact_id = cc.contact_id and cd2.name = 'suburb'
  left join lookups l2 on cd2.value = l2.code and l2.arch_short_name = 'lookup.suburb'
  left join contact_details cd3 on cd3.contact_id = cc.contact_id and cd3.name = 'postcode'
  left join contact_details cd4 on cd4.contact_id = cc.contact_id and cd4.name = 'state'
  left join contact_details cd5 ON cd5.contact_id = cc.contact_id and cd5.name = 'preferred'
  left join contact_classifications ccl ON ccl.contact_id = cc.contact_id
  left join lookups lcl ON lcl.lookup_id = ccl.lookup_id
  left join entity_details d1 on d1.entity_id = p.entity_id and d1.name = 'dateOfBirth'
  left join entity_details d2 on d2.entity_id = p.entity_id and d2.name = 'desexed'
  left join entity_details d3 on d3.entity_id = p.entity_id and d3.name = 'deceased'
  left join entity_details d4 on d4.entity_id = p.entity_id and d4.name = 'species'
  left join lookups l4 on l4.code = d4.value and l4.arch_short_name = 'lookup.species'
  left join entity_details d5 on d5.entity_id = p.entity_id and d5.name = 'breed'
  left join lookups l5 on l5.code = d5.value and l5.arch_short_name = 'lookup.breed'
where
  pa.arch_short_name like 'act.customerAccountCharges%' and
  pa.activity_start_time between $P{Sale Start} and date_add($P{Sale End}, INTERVAL '23:59:59' HOUR_SECOND) and
  pr.name like $P{Product} and
  pt.name like $P{Product Type} and
  p.active = 1 and
  c.active = 1 and
  l4.name like $P{Species} and
  d5.value like $P{Breed} and
  d1.value between $P{DOB Start} and $P{DOB End}
group by c.entity_id, rank
order by c.name, c.entity_id,rank desc, cc.contact_id desc

and in the report we group by id and do all the output in the group header and have nothing in the detail band - ie:

The explanatory text says:

(and we get the newest by sorting on the contact_id descending).

Regards, Tim G

Syndicate content