* Jasper Bijl
> Is there a way to do something like subqueries in one query?

Yes, JOIN can be used in many cases where you would think you need
sub-queries. A JOIN is also generally faster, according to:

<URL: http://www.mysql.com/doc/en/ANSI_diff_Subqueries.html >

> I have a customer table (Klant) with contacts (KlantKontakt) and a
> address (Adres) table.
> The address table keeps a record of each different address for a
> customer including old addresses (to maintain history).

ok... and there is a date column or similar in the Adres table, to keep
track of which address is the last, I suppose. Let's call it 'FromDate'.

You could add a column in Adres:

  state enum('active','inactive')

...and update the previous active address and set it to 'inactive' when you
insert a new one, but that would be redundant, because the latest always is
the active, right?

> If I want to retrieve a list of customers with their newest address, I
> have to do a max() to retreive the last address.

You should take a look at this:

<URL: http://www.mysql.com/doc/en/example-Maximum-column-group-row.html >

The "MAX-CONCAT trick" can maybe solve your prolem?

> I can do this in PHP in a seperate query but I like to do it in one
> query on the mysql prompt.
>
> Below is my (wrong) query:
>
> SELECT
> Klant.klantcode, Klant.naam,
> KlantKontakt.persooncode, KlantKontakt.Achternaam,
> Adres.straat, Adres.postcode, Adres.plaats
>
> FROM Klant, KlantKontakt, Adres
>
> WHERE SoortKlant = 'Prospect'
> AND Klant.klantcode = KlantKontakt.klantcode
> AND Adres.klantcode = Klant.klantcode
>
> ORDER BY Klant.Naam
>
>
> Is there any way to do this in MySQL in one query?

It's hard to see what's wrong with the query above... except, of course, it
does not select the latest address. :)

There is another approach (in addition to subqueries if you use 4.1, or
temporary tables, or the MAX-CONCAT trick). You could try using a self join.
The date column in the Adres table is called 'FromDate', at least in my
mind. :)

The same query as above, but with an additional join on the address:

SELECT
  Klant.klantcode, Klant.naam,
  KlantKontakt.persooncode, KlantKontakt.Achternaam,
  Adres.straat, Adres.postcode, Adres.plaats

  FROM Klant, KlantKontakt, Adres

  LEFT JOIN Adres AS A2 ON
    A2.klantcode = Klant.klantcode AND
    A2.FromDate > Adres.FromDate

  WHERE SoortKlant = 'Prospect'
  AND Klant.klantcode = KlantKontakt.klantcode
  AND Adres.klantcode = Klant.klantcode

  AND A2.klantcode IS NULL

  ORDER BY Klant.Naam

We join any later address, if it's found we do _not_ want the row in our
result. This is achieved by testing if A2.klantcode IS NULL.

Warning: For each customer, the server will do a lookup on all later
addresses for each address... this will be very slow when you have very many
addresses for each customer. In your case, I would guess you rarly have more
than 10-15 address rows per customer, so you should be safe. If my
assumptions are wrong, and you have, say, 1000 address rows per customer,
the self join approach will probably be too slow. The server would have to
read 500.000 Adres rows for each customer (the first Adres would join to the
999 later, the second Adres would join to the 998 later, and so on).

--
Roger


-- 
MySQL General Mailing List
For list archives: http://lists.mysql.com/mysql
To unsubscribe:    http://lists.mysql.com/[EMAIL PROTECTED]

Reply via email to