DarrenNavitas
DarrenNavitas

Reputation: 239

SQL - Table join where primary key in first table is part of key in second

Hi I am fairly new to SQL - so be gentle with me!

I basically have two tables that I am trying to join where the primary key in the first table is used multiple times in the second table (and forms the primary key in the second table along with another column)

It's probably best if I provide an example:

Table 1 : TravelRecords

TravelEventID  EventType  RecordLocator  OfficeID    
 0001            F          ABC123         LDN  
 0002            F          ABC234         LDN  
 0003            T          BDF232         SOU  
 0004            F          DFD890         GLA  

Table 2 : TravelRecordRmks

TravelEventID  RemarkNo    Keyword       Text  
 0001            1           TVL          LOWCOST BOOKING  
 0001            2           TVL          CREDIT CARD USED  
 0001            3           PSG          COST CENTRE REQUIRED  
 0001            4           PSG          EMPLOYEE NUM REQUIRED
 0002            1           TVL          CREDIT CARD USED
 0002            2           AGT          BOOKED BY AGENT
 0002            3           AGT          CONFIRM WITH AIRLINE
 0002            4           TVL          LOWEST FARE CONFIRMED
 0002            5           TVL          NO CANCELLATION CHARGE
 0003            1           TVL          LOWCOST BOOKING
 0003            2           TVL          CARRIER : EASYJET
 0003            3           TVL          LOWEST FARE CONFIRMED
 0004            1           TVL          LOWCOST BOOKING
 0004            2           TVL          CREDIT CARD USED

For the second table the key is the combination of the TravelEventID and the RemarkNo which combined gives a unique ID.

Basically all I am trying to do is join the tables together and return the record locator for bookings that have a remark text line of LOWCOST BOOKING AND CREDIT CARD USED (so in the example above only ABC123 and DFD890 should be returned.

I've tried something along the lines of :

SELECT  TravelRecords.RecordLocator
FROM    TravelRecords INNER JOIN
        TravelRecordRmks ON TravelRecords.TravelEventID = TravelRecordRmks.TravelEventID db  
WHERE   (TravelRecordRmks.RemarkText = 'LOWCOST BOOKING') 
        and (TravelRecordRmks.RemarkText = 'CREDIT CARD USED')
ORDER BY dbo.vw_gTravelOrderEvent.RecordLocator

However - that returns nothing. This is probably really simple - but I can't get it to return the required response when I am looking for the single TravelEventID to contain both Remark Text fields.

Any help much appreciated Cheers

Upvotes: 2

Views: 5280

Answers (6)

Andomar
Andomar

Reputation: 238296

The most readable way to check this is probably a double where exists, like:

SELECT  tr.*
FROM    TravelRecords tr
WHERE EXISTS (
    SELECT * FROM TravelRecordRmks trr 
    WHERE trr.TravelEventID = tr.TravelEventID
    AND trr.RemarkText = 'LOWCOST BOOKING'
)
AND EXISTS (
    SELECT * FROM TravelRecordRmks trr 
    WHERE trr.TravelEventID = tr.TravelEventID
    AND trr.RemarkText = 'CREDIT CARD USED'
)

An alternative that might perform better, using an inner join subquery as a filter:

SELECT  tr.*
FROM    TravelRecords tr
INNER JOIN (
        SELECT TravelEventID
        FROM TravelRecordRmks trr 
        WHERE RemarkText IN ('CREDIT CARD USED','LOWCOST BOOKING')
        GROUP BY TravelEventID
        HAVING COUNT(DISTINCT RemarkText) = 2
) filter 
ON      filter.TravelEventID = tr.TravelEventID

The HAVING COUNT(DISTINCT RemarkText) = 2 makes sure that both types of remarks are found.

Upvotes: 5

Tom H
Tom H

Reputation: 47402

In addition to Andomar's IF EXISTS logic, another way that you could do it would be two joins to the remarks table:

SELECT
     TR.record_locator,
FROM
     Travel_Records TR
INNER JOIN Travel_Record_Remarks TRR1 ON
     TRR1.travel_event_id = TR.travel_event_id AND
     TRR1.remark_text = 'LOWCOST BOOKING'
INNER JOIN Travel_Record_Remarks TRR2 ON
     TRR2.travel_event_id = TR.travel_event_id AND
     TRR2.remark_text = 'CREDIT CARD USED'

There is a flaw with this statement though, which is that if a travel event has two remarks with the same text then you might end up getting back multiple rows with the same record locator.

Upvotes: 2

Donnie
Donnie

Reputation: 46943

You can't use an and like that to check for values that occur on multiple rows. The best you can do is use an or and count to make sure you match the number of conditions that you want. Something like:

select
  tr.RecordLocator
from
  TravelRecords tr
  join (
    select 
      r.TravelEventID,
      count(*)
    from
      TravelRecords r
      join TravelRecordRmks rr on r.TravelEventID = rr.TravelEventID
    where
      rr.Text = 'LOWCOST BOOKING' or rr.Text = 'CREDIT CARD USED'
    group by
      r.TravelEventID
    having
      count(*) = 2   -- must match both (or have one of them twice) for a single TravelEventID
  ) x on x.TravelEventID = tr.TravelEventID
order by
  tr.RecordLocator

Upvotes: 1

Larry Lustig
Larry Lustig

Reputation: 50998

The problem is with your AND condition. You are asking for records from TravelRecordRmks where it is true that the RemarkText field is 'LOWCOST BOOKING' and simultaneously is 'CREDIT CARD USED'.

What you want is:

   WHERE RemarkText IN ('LOWCOST BOOKING', 'CREDIT CARD USED')

which will find lines containing either value.

Upvotes: 0

TLiebe
TLiebe

Reputation: 7996

Try something like this:

SELECT DISTINCT
  tr.RecordLocator
FROM
  TravelRecords tr
  INNER JOIN TravelRecordRmks rmk
    ON tr.TravelEventID = rmk.TravelEventID
WHERE
  rmk.RemarkText = 'LOWCOST BOOKING'
  OR rmk.RemarkText = 'CREDIT CARD USED'
ORDER BY
  tr.RecordLocator

Upvotes: 0

JasDev
JasDev

Reputation: 736

WHERE   (TravelRecordRmks.RemarkText = 'LOWCOST BOOKING') 
        and (TravelRecordRmks.RemarkText = 'CREDIT CARD USED')

It looks like you need OR instead of AND.

SQL boolean logic (OR and AND) is not interpreted the same way as everyday English.

Upvotes: 2

Related Questions