Informix subconsulta con PRIMERA opción
-
06-07-2019 - |
Pregunta
¿Cuál es la mejor manera de transcribir el siguiente código Transact-SQL a Informix Dynamic Server (IDS) 9.40:
Objetivo: necesito los primeros 50 pedidos con sus respectivas líneas de pedido
select *
from (select top 50 * from orders) a inner join lines b
on a.idOrder = b.idOrder
Mi problema es con la subselección porque Informix no permite la PRIMERA opción en la subselección.
¿Alguna idea simple?
Solución
La respuesta oficial sería 'Actualice desde IDS 9.40 ya que IBM ya no lo admite'. Es decir, IDS 9.40 no es una versión actual, y (idealmente) no debería usarse.
Solución para IDS 11.50
Usando IDS 11.50, puedo escribir:
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
;
Esto es más o menos equivalente a su consulta. En consecuencia, si usa una versión actual de IDS, puede escribir la consulta usando casi la misma notación que en Transact-SQL (usando FIRST en lugar de TOP).
Solución para IDS 9.40
¿Qué puedes hacer en IDS 9.40? Disculpe un momento ... Tengo que ejecutar mi servidor IDS 9.40.xC7 (este fixpack fue lanzado en 2005; la versión original probablemente fue a fines de 2003) ...
Primer problema: IDS 9.40 no permite subconsultas en la cláusula FROM.
Segundo problema: IDS 9.40 no permite la notación 'PRIMERO n' en ninguno de estos contextos:
SELECT FIRST 10 * FROM elements INTO TEMP e;
INSERT INTO e SELECT FIRST 10 * FROM elements;
Tercer problema: IDS 9.40 no tiene un ROWNUM simple.
Entonces, para solucionar estos problemas, podemos escribir (usando una tabla temporal; lo eliminaremos más adelante):
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;
Esto produce la misma respuesta que la consulta única en IDS 11.50. ¿Podemos evitar la mesa temporal? Sí, pero es más detallado:
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;
Aplicar eso a los pedidos originales más el ejemplo de líneas de pedido se deja como ejercicio para el lector.
Subconjunto relevante de esquema para 'Tabla de elementos':
-- 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)
);
Salida (en mi base de datos de muestra):
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
Otros consejos
Si entiendo su pregunta, tiene un problema con "TOP". Intente usar una consulta TOP-N.
Por ejemplo:
select *
from (SELECT *
FROM foo
where foo_id=[number]
order by foo_id desc)
where rownum <= 50
Esto le dará los primeros cincuenta resultados (porque ordeno por desc en la subconsulta)