Sottoquery Informix con la PRIMA opzione
-
06-07-2019 - |
Domanda
Qual è il modo migliore per trascrivere il seguente codice Transact-SQL in Informix Dynamic Server (IDS) 9.40:
Obiettivo: ho bisogno dei primi 50 ordini con le rispettive righe di ordine
select *
from (select top 50 * from orders) a inner join lines b
on a.idOrder = b.idOrder
Il mio problema è con la sottoselezione perché Informix non consente la PRIMA opzione nella sottoselezione.
Qualche idea semplice ?.
Soluzione
La risposta ufficiale sarebbe "Si prega di aggiornare da IDS 9.40 poiché non è più supportato da IBM". Cioè, IDS 9.40 non è una versione corrente e (idealmente) non dovrebbe essere utilizzato.
Soluzione per IDS 11.50
Utilizzando IDS 11.50, posso scrivere:
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
;
Questo è più o meno equivalente alla tua query. Di conseguenza, se si utilizza una versione corrente di IDS, è possibile scrivere la query utilizzando quasi la stessa notazione di Transact-SQL (utilizzando FIRST al posto di TOP).
Soluzione per IDS 9.40
Cosa puoi fare in IDS 9.40? Mi scusi un momento ... Devo avviare il mio server IDS 9.40.xC7 (questo fix pack è stato rilasciato nel 2005; la versione originale era probabilmente alla fine del 2003) ...
Primo problema: IDS 9.40 non consente le query secondarie nella clausola FROM.
Secondo problema - IDS 9.40 non consente la "PRIMA notazione" in nessuno di questi contesti:
SELECT FIRST 10 * FROM elements INTO TEMP e;
INSERT INTO e SELECT FIRST 10 * FROM elements;
Terzo problema - IDS 9.40 non ha un semplice ROWNUM.
Quindi, per ovviare a questi, possiamo scrivere (usando una tabella temporanea - lo rimuoveremo in seguito):
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;
Questo produce la stessa risposta della singola query in IDS 11.50. Possiamo evitare la tabella temporanea? Sì, ma è più dettagliato:
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;
Applicando questo agli ordini originali più l'esempio delle righe d'ordine viene lasciato come esercizio per il lettore.
Sottoinsieme pertinente di schema per "Tabella degli elementi":
-- 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 (sul mio database di esempio):
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
Altri suggerimenti
Se capisco la tua domanda, stai riscontrando un problema con " TOP " ;. Prova a utilizzare una query TOP-N.
Ad esempio:
select *
from (SELECT *
FROM foo
where foo_id=[number]
order by foo_id desc)
where rownum <= 50
In questo modo otterrai i primi cinquanta risultati (perché ordino per descrizione nella sottoquery)