简体   繁体   中英

Selecting rows from table based on resultset

I've been trying to work with languages in databases for a little while, but this one has me stumped.

So here's the simplified structure of two tables

DATA
descID     | descOriginal | deptID | Other Data
-----------|--------------|------- |-----------
10         | TshirtsNL    | 1      | ...
20         | TrousersNL   | 1      | ...
30         | ShoesNL      | 1      | ...

and

LANG
descID     |descTranslated| langID
-----------|--------------|-------
10         | TshirtsDE    | 1
10         | TshirtsFR    | 2
10         | TshirtsEN    | 3

So basically, the original description sits in the first table, along with other needed data. However, the translated description sits in another table for when the original description needs to be translated.

To complicate things further: Not all rows in the LANG table have been filled to correspond with the data in the DATA table (this only happens when the customer fills in their translation). This means I can't rely on a simple JOIN WHERE l.descID = d.descID .

I've been trying different kinds of joins and coalesce, but I can't seem to make it work.

Below is not supported in my Firebird version (1.5), but might work if your Database supports derived tables.

I thought something like this could work:

SELECT COALESCE(lang.descTranslated, data.descOriginal) AS desc
        FROM
            (SELECT descID, descOriginal FROM data WHERE deptID = 
             :deptID) data
        LEFT JOIN
            (SELECT descID, descTranslated FROM lang) lang
        ON
            data.descID = lang.descID

But Firebird doesn't seem to like these kind of statements (or I'm missing something), because the following test SQL throws an error "unknown token SELECT"

SELECT *  FROM (SELECT descID FROM data)

As already commented by Val Marinov, derived tables were introduced in Firebird 2.0 (in 2006). However for your problem, you don't need to use derived tables:

To get the result you want:

select coalesce(lang.desctranslated, data.descoriginal)
from data 
left join lang
  on data.descid = lang.descid

is sufficient. If you want to specify a specific language, then using the following would suffice:

select coalesce(lang.desctranslated, data.descoriginal)
from data 
left join lang
  on data.descid = lang.descid
where lang.langid = 2 or lang.langid is null

or pushing the condition down to the join:

select coalesce(lang.desctranslated, data.descoriginal)
from data 
left join lang
  on data.descid = lang.descid and lang.langid = 2

I have tested this with Firebird 1.5.6 and the sample data from your question.

While Firebird 1.x did not support anonymous derived tables it did support views.

CREATE VIEW DEPT_DESCS AS
  SELECT lang.descID, lang.descTranslated as Dept_Description, lang.langID, languages.lang_name 
  FROM lang 
  LEFT JOIN DATA ON DATA.descID = lang.descID
  JOIN languages ON languages.lang_id = lang.langID
  WHERE DATA.descID is not null -- would not need translations for non-existing lines
  ORDER BY lang.descID, lang.langID DESC
UNION ALL
  SELECT data.descID, data.descOriginal, NULL, NULL FROM data

And now you can select from that view

SELECT first(1) * FROM DEPT_DESCS 
WHERE ( langID in (5,8,10) or langID is NULL )
  AND descID=10
ORDER by langID /* DESC */ NULLS LAST

See https://www.firebirdsql.org/manual/nullguide-sorts.html

One may also use zero or negative number instead of null for non-translated descriptions.

CREATE VIEW DEPT_DESCS AS
  SELECT lang.descID, lang.descTranslated as Dept_Description, lang.langID, languages.lang_name 
  .....
  ORDER BY lang.descID, lang.langID DESC
UNION ALL
  SELECT data.descID, data.descOriginal, -100 /* or 0 */, NULL FROM data

That way the second query gets a bit more simple.

SELECT first(1) * FROM DEPT_DESCS 
WHERE langID in (5,8,10, -100 /* or 0 */ ) 
  AND descID=10
ORDER by langID DESC 

However this use of magic constants would obviously demand that

  1. Never any language with the said MC (ID = 0 or ID = -100) be actually added, never ever.
  2. The query constructor when forming then in-list would always add the MC to it, while in NULLs-based way it would only put there actual values and NULL is accounted for separately, in the query template itself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM