views:

1611

answers:

2

What is the best way of transcribing the following Transact-SQL code to Informix Dynamic Server (IDS) 9.40:

Objective: I need the first 50 orders with their respective order lines

select *
    from (select top 50 * from orders) a inner join lines b
            on a.idOrder = b.idOrder

My problem is with the subselect because Informix does not allow the FIRST option in the subselect.

Any simple idea?.

A: 

If I understand your question you are having a problem with "TOP". Try using a TOP-N query.

For example:

select  *
  from  (SELECT  *
           FROM  foo
          where  foo_id=[number]
       order by  foo_id desc)
 where  rownum <= 50

This will get you the top fifty results (because I order by desc in the sub query)

northpole
Would be a possible solution, but in Informix is not easy get the row num. See http://stackoverflow.com/questions/119278/row-numbers-for-a-query-in-informix.If it is possible I don't want nor use temporary tables and sequences.
Moncho
`rownum` is not Informix SQL. That will only (?) work for Oracle.
sleske
+3  A: 

The official answer would be 'Please upgrade from IDS 9.40 since it is no longer supported by IBM'. That is, IDS 9.40 is not a current version - and should (ideally) not be used.

Solution for IDS 11.50

Using IDS 11.50, I can write:

SELECT *
    FROM (SELECT FIRST 10 * FROM elements) AS e
         INNER JOIN compound_component AS a
            ON e.symbol = a.element
         INNER JOIN compound AS c
            ON c.compound_id = a.compound_id
    ;

This is more or less equivalent to your query. Consequently, if you use a current version of IDS, you can write the query using almost the same notation as in Transact-SQL (using FIRST in place of TOP).

Solution for IDS 9.40

What can you do in IDS 9.40? Excuse me a moment...I have to run up my IDS 9.40.xC7 server (this fix pack was released in 2005; the original release was probably in late 2003)...

First problem - IDS 9.40 does not allow sub-queries in the FROM clause.

Second problem - IDS 9.40 does not allow 'FIRST n' notation in either of these contexts:

SELECT FIRST 10 * FROM elements INTO TEMP e;
INSERT INTO e SELECT FIRST 10 * FROM elements;

Third problem - IDS 9.40 doesn't have a simple ROWNUM.

So, to work around these, we can write (using a temporary table - we'll remove that later):

SELECT e1.*
    FROM elements AS e1, elements AS e2
    WHERE e1.atomic_number >= e2.atomic_number
    GROUP BY e1.atomic_number, e1.symbol, e1.name, e1.atomic_weight, e1.stable
    HAVING COUNT(*) <= 10
    INTO TEMP e;

SELECT *
    FROM e INNER JOIN compound_component AS a
                   ON e.symbol = a.element
           INNER JOIN compound AS c
                   ON c.compound_id = a.compound_id;

This produces the same answer as the single query in IDS 11.50. Can we avoid the temporary table? Yes, but it is more verbose:

SELECT e1.*, a.*, c.*
    FROM  elements AS e1, elements AS e2, compound_component AS a,
           compound AS c
    WHERE e1.atomic_number >= e2.atomic_number
      AND e1.symbol = a.element
      AND c.compound_id = a.compound_id
    GROUP BY e1.atomic_number, e1.symbol, e1.name, e1.atomic_weight,
             e1.stable, a.compound_id, a.element, a.seq_num,
             a.multiplicity, c.compound_id, c.name
    HAVING   COUNT(*) <= 10;

Applying that to the original orders plus order lines example is left as an exercise for the reader.


Relevant subset of schema for 'Table of Elements':

-- See: http://www.webelements.com/ for elements.
-- See: http://ie.lbl.gov/education/isotopes.htm for isotopes.

CREATE TABLE elements
(
    atomic_number   INTEGER NOT NULL UNIQUE CONSTRAINT c1_elements
                    CHECK (atomic_number > 0 AND atomic_number < 120),
    symbol          CHAR(3) NOT NULL UNIQUE CONSTRAINT c2_elements,
    name            CHAR(20) NOT NULL UNIQUE CONSTRAINT c3_elements,
    atomic_weight   DECIMAL(8,4) NOT NULL,
    stable          CHAR(1) DEFAULT 'Y' NOT NULL
                    CHECK (stable IN ('Y', 'N'))
);

CREATE TABLE compound
(
    compound_id     SERIAL NOT NULL PRIMARY KEY,
    name            VARCHAR(100) NOT NULL UNIQUE
);

-- The sequence number is used to order the components within a compound.

CREATE TABLE compound_component
(
    compound_id     INTEGER REFERENCES compound,
    element         CHAR(3) NOT NULL REFERENCES elements(symbol),
    seq_num         SMALLINT DEFAULT 1 NOT NULL
                    CHECK (seq_num > 0 AND seq_num < 20),
    multiplicity    INTEGER NOT NULL
                    CHECK (multiplicity > 0 AND multiplicity < 20),
    PRIMARY KEY(compound_id, seq_num)
);

Output (on my sample database):

 1 H   Hydrogen        1.0079 Y     1 H    1     2       1 water
 1 H   Hydrogen        1.0079 Y     3 H    2     4       3 methane
 1 H   Hydrogen        1.0079 Y     4 H    2     6       4 ethane
 1 H   Hydrogen        1.0079 Y     5 H    2     8       5 propane
 1 H   Hydrogen        1.0079 Y     6 H    2    10       6 butane
 1 H   Hydrogen        1.0079 Y    11 H    2     5      11 ethanol
 1 H   Hydrogen        1.0079 Y    11 H    4     1      11 ethanol
 6 C   Carbon         12.0110 Y     2 C    1     1       2 carbon dioxide
 6 C   Carbon         12.0110 Y     3 C    1     1       3 methane
 6 C   Carbon         12.0110 Y     4 C    1     2       4 ethane
 6 C   Carbon         12.0110 Y     5 C    1     3       5 propane
 6 C   Carbon         12.0110 Y     6 C    1     4       6 butane
 6 C   Carbon         12.0110 Y     7 C    1     1       7 carbon monoxide
 6 C   Carbon         12.0110 Y     9 C    2     1       9 magnesium carbonate
 6 C   Carbon         12.0110 Y    10 C    2     1      10 sodium bicarbonate
 6 C   Carbon         12.0110 Y    11 C    1     2      11 ethanol
 8 O   Oxygen         15.9990 Y     1 O    2     1       1 water
 8 O   Oxygen         15.9990 Y     2 O    2     2       2 carbon dioxide
 8 O   Oxygen         15.9990 Y     7 O    2     1       7 carbon monoxide
 8 O   Oxygen         15.9990 Y     9 O    3     3       9 magnesium carbonate
 8 O   Oxygen         15.9990 Y    10 O    3     3      10 sodium bicarbonate
 8 O   Oxygen         15.9990 Y    11 O    3     1      11 ethanol
Jonathan Leffler
Just a note: "IDS 9.40 does not allow sub-queries in the FROM clause." While this is technically true, you can use `SELECT * FROM table(multiset( SELECT * FROM xxx... ))` - this is essentially the same as a true ANSI derived table. There are some restrictions on what you may do in the inner SELECT, but mostly it works.
sleske
@sleske: yes, you're correct - and that is available from fairly early 9.x versions of IDS, all of which are officially obsolete.
Jonathan Leffler