Received: from localhost (maia-4.hub.org [200.46.204.183]) by postgresql.org (Postfix) with ESMTP id 94E849FB69A for ; Wed, 6 Jun 2007 03:55:37 -0300 (ADT) Received: from postgresql.org ([200.46.204.71]) by localhost (mx1.hub.org [200.46.204.183]) (amavisd-maia, port 10024) with ESMTP id 02336-01 for ; Wed, 6 Jun 2007 03:55:33 -0300 (ADT) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.5 Received: from svr4.postgresql.org (svr4.postgresql.org [66.98.251.159]) by postgresql.org (Postfix) with ESMTP id 8F94E9FB697 for ; Wed, 6 Jun 2007 03:55:33 -0300 (ADT) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.3 Received: from out1.smtp.messagingengine.com (out1.smtp.messagingengine.com [66.111.4.25]) by svr4.postgresql.org (Postfix) with ESMTP id EFEC85AF074 for ; Wed, 6 Jun 2007 06:55:32 +0000 (GMT) Received: from compute1.internal (compute1.internal [10.202.2.41]) by out1.messagingengine.com (Postfix) with ESMTP id C855F23756E for ; Wed, 6 Jun 2007 02:55:30 -0400 (EDT) Received: from heartbeat1.messagingengine.com ([10.202.2.160]) by compute1.internal (MEProxy); Wed, 06 Jun 2007 02:55:30 -0400 X-Sasl-enc: qSyvuZ24MkyoeINd/a9ky/njbVuKwzmhn5Iiug9X3rc1 1181112930 Received: from [17.203.38.135] (A17-203-38-135.apple.com [17.203.38.135]) by mail.messagingengine.com (Postfix) with ESMTP id 61EA92D287 for ; Wed, 6 Jun 2007 02:55:30 -0400 (EDT) Mime-Version: 1.0 (Apple Message framework v752.3) Content-Transfer-Encoding: 7bit Message-Id: <4FD9368D-D4CA-44CF-887B-EBB64DCE46BA@fastmail.fm> Content-Type: text/plain; charset=US-ASCII; delsp=yes; format=flowed To: pgsql-sql@postgresql.org From: Drew Subject: How to find missing values across multiple OUTER JOINs Date: Tue, 5 Jun 2007 23:55:28 -0700 X-Mailer: Apple Mail (2.752.3) X-Virus-Scanned: Maia Mailguard 1.0.1 X-Spam-Status: No, hits=0.001 tagged_above=0 required=5 tests=BAYES_50=0.001 X-Spam-Level: X-Archive-Number: 200706/48 X-Sequence-Number: 28538 I'm having troubles using multiple OUTER JOINs, which I think I want to use to solve my problem. My problem is to find all non-translated string values in our translations database, given the 4 following tables: SOURCE (source_id PRIMARY KEY, language_id, value, ...) TRANSLATION (translation_id PRIMARY KEY, language_id, value, ...) TRANSLATION_PAIR (source_id, translation_id) LANGUAGE(language_id PRIMARY KEY, name) This seems to me the appropriate situation for using OUTER JOINs, but I cannot figure out how to get the null rows without the not-null rows. Here's my best guess at this query: SELECT s.source_id,tp.translation_pair_id,t.translation_id,t.language_id, l.name FROM source s LEFT OUTER JOIN translation_pair tp USING(source_id) LEFT OUTER JOIN translation t ON tp.translation_id = t.translation_id AND t.translation_id is null) RIGHT OUTER JOIN language l on l.language_id = t.language_id; To test this query, I have a string that only has a translation in English and used it in this test query. SELECT s.source_id,tp.translation_pair_id,t.translation_id,t.language_id, l.name FROM (select * FROM source s WHERE source_id = 159986) as s LEFT OUTER JOIN translation_pair tp USING(source_id) LEFT OUTER JOIN translation t ON tp.translation_id = t.translation_id RIGHT OUTER JOIN language l on l.language_id = t.language_id; This yields promising results: source_id | translation_pair_id | translation_id | language_id | name -----------+---------------------+----------------+------------- +---------------------- | | | | Russian | | | | Danish | | | | Dutch 159986 | 1893187 | 1743833 | 4 | English | | | | Finnish | | | | French | | | | German | | | | Italian | | | | Japanese | | | | Korean | | | | Norwegian | | | | Simplified Chinese | | | | Spanish | | | | Swedish | | | | Traditional Chinese | | | | Portuguese | | | | Polish | | | | Turkish | | | | Czech | | | | Brazilian Portuguese (20 rows) However, when I try to exclude the one not-null row, doing this: SELECT s.source_id,tp.translation_pair_id,t.translation_id,t.language_id, l.name FROM (select * FROM source s WHERE source_id = 159986) AS s LEFT OUTER JOIN translation_pair tp USING(source_id) LEFT OUTER JOIN translation t ON tp.translation_id = t.translation_id AND t.translation_id IS NULL RIGHT OUTER JOIN language l on l.language_id = t.language_id; I expect 19 rows, but instead get 20 rows, all containing null values. source_id | translation_pair_id | translation_id | language_id | name -----------+---------------------+----------------+------------- +---------------------- | | | | Russian | | | | Danish | | | | Dutch | | | | English | | | | Finnish | | | | French | | | | German | | | | Italian | | | | Japanese | | | | Korean | | | | Norwegian | | | | Simplified Chinese | | | | Spanish | | | | Swedish | | | | Traditional Chinese | | | | Portuguese | | | | Polish | | | | Turkish | | | | Czech | | | | Brazilian Portuguese (20 rows) I'm guessing I need to group the joins together, to avoid some associative problem. Do you see what I'm doing wrong? Thanks for the help, Drew