J'ai une table dont le schéma est comme ceci:
CREATE TABLE product_shipping(
product_id CHAR(10),
product_name CHAR(10),
deal_dt DATETIME,
deal_reason_no SMALLINT,
cancel_dt DATETIME,
cancel_reason_no SMALLINT
);
Une fois que la date d'expédition est organisée, le transal_dt and Deal_Reason_no sera défini et Annuler_dt et Annuler_Reason_no est NULL. Cependant, Product_ID n'est pas unique dans le tableau car chaque produit peut être annulé. Une fois annulé Cancel_dt et Annuler_Reason_NO sera défini. Si le produit annulé est acheté par d'autres clients, l'expédition est enregistrée dans la nouvelle ligne et que le nom de produit peut être modifié dans la nouvelle expédition.
Je veux interroger le produit_id et deal_dt dont Deal_Reason_no est 1, 3 ou 5 et Deal_DT est entre '2014-04-01 00:00:00'
et '2014-04-11 00:00:00'
et le Dernière précédente Deal_DT et Dernier annoncez Annuler_DT dont Cancel_Reason_no est 2 ou 4 pour le produit_ID.
Je pense que le SQL pourrait être comme ça:
SELECT
C.product_id as product_id,
C.deal_dt as deal_dt,
R.deal_dt as previous_deal_dt,
R.cancel_dt as previous_cancel_dt,
FROM product_shipping C
LEFT JOIN product_shipping R ON (???)
WHERE TO_CHAR(C.deal_reason_no ) in ('1', '3', '5')
AND C.deal_dt between '2014-04-01 00:00:00' and '2014-04-11 00:00:00'
Mais je ne suis pas sûr de savoir comment rejoindre le dernier enregistrement précédent.
J'utilise Informix 11.70.
Edit: Ajoutez mon idée. Est-ce raisonnable?
SELECT
C.product_id as product_id,
C.deal_dt as deal_dt,
MAX(R.deal_dt) as previous_deal_dt,
MAX(R.cancel_dt) as previous_cancel_dt,
FROM product_shipping C
LEFT JOIN product_shipping R ON (C.product_id = R.product_id and TO_CHAR(R.cancel_reason_no) MATCHES ('2', '4') and R.cancel_dt <= C.deal_dt)
WHERE TO_CHAR(C.deal_reason_no ) in ('1', '3', '5')
AND C.deal_dt between '2014-04-01 00:00:00' and '2014-04-11 00:00:00'
GROUP BY 1,2
Je vous suggère de vous connecter à des produits précédents qui correspondent aux critères et (s'il existe des existents) réduisent à celui où il n'y a pas de ligne ultérieure existe :=:
SELECT P.product_id AS product_id,
,P.deal_dt AS deal_dt
,C.deal_dt AS previous_deal_dt
,C.cancel_dt AS previous_cancel_dt
FROM product_shipping p
LEFT JOIN product_shipping C ON C.product_id = P.product_id
AND C.cancel_reason_no IN (2, 4)
AND C.cancel_dt < P.deal_dt
WHERE P.deal_reason_no IN (1, 3, 5)
AND P.deal_dt BETWEEN '2014-04-01 00:00:00' AND '2014-04-11 00:00:00'
AND NOT EXISTS (
SELECT 1
FROM product_shipping C1
WHERE C1.product_id = C.product_id
AND C1.cancel_reason_no IN (2, 4)
AND C1.cancel_dt < P.deal_dt
AND C1.cancel_dt > C.deal_dt
);
En supposant que (product_id,cancel_dt)
Soit UNIQUE
, sinon, vous avez besoin de critères d'embrouillage pour être sans ambiguïté. De cette façon, vous n'avez pas besoin de GROUP BY
, Car une seule ligne (ou non) est rejointe.
En supposant également deal_dt
Et cancel_dt
Sont censés venir du même Annulé Deal.
Ce serait plus simple avec la fonction de fenêtre lag()
, mais votre version ne semble pas supporter cela en fonction de la discussion sous le fichier POST DUPLICAT .
En supposant que vous avez une version assez récente, InfoMix prend en charge les fonctions LAG
et LEAD
sur les opérations de classement, voir http://www-01.ibm.com/support/knowdgeCenter/ Ssgu8g_12.1.0/com.ibm.sqls.doc/ids_sqs_1513.htm
Celles-ci ne fonctionnent que si la ligne actuelle et celle que vous considérez que la ligne précédente se trouvent à l'aide des mêmes clauses de filtrage, sinon vous et avez besoin de référencer le tableau trois fois: d'abord trouver la (s) rangée (s) de base vous intéresse Ensuite, joint ensuite à cela pour trouver des lignes précédentes à considérer, et troisièmement, soit une sous-requête extérieure gauche, soit une sous-requête corrélée à la fois pour exclure des lignes supplémentaires s'il peut y avoir plusieurs critères "à la ligne perméable". Si la sous-requête ou l'option de jointure supplémentaire est plus efficace que l'autre dépend de votre planificateur de requête de votre DBMS et de vos critères de recherche, vous vous suggérez donc d'essayer des données de test réalistes pour les repasser.
Par exemple:
SELECT <things>
FROM sometable AS current
LEFT OUTER JOIN sometable AS older
ON older.refdate<current.refdate
AND <filters on older to find rows that match the "previous row" criteria>
LEFT OUTER JOIN some table AS middle
ON middle.refdate<current.refdate AND middle.refdate>older.refdate
AND <filters on middle to find rows that match the "previous row" criteria>
WHERE <filters to find current row or rows>
AND middle.refdate IS NULL
La vérification null sur la partie intermédiaire dans la clause WHERE au lieu de la clause de jointure signifie que toute combinaison où il y a une rangée plus récente que celle correspondue par la jointure "plus âgée", donc vous savez "actuel" est la ligne actuelle et " Plus vieux "est la rangée la plus récente avant celle qui correspond aux critères" rangée précédente ".
Si vous savez qu'il y aura toujours au moins une ligne précédente pour chaque ligne trouvée dans "Current", la jointure "plus âgée" peut être une jointure interne qui peut permettre au coureur de requête d'être plus efficace.
Si vous recherchez des critères pour les lignes actuelles et précédentes sont les mêmes (à l'exception de la vérification des angots relatifs du cours), utilisez-le, alors l'utilisation de LAG()
devrait être loin plus efficace que vous n'avez pas besoin de l'une des deux autres références à la table.
Je ne sais pas comment rejoindre pour obtenir le dernier enregistrement précédent.
Commencer là. Obtenez le dernier enregistrement précédent avec une jointure auto-rejoindre:
select c.product_id, min(p.deal_dt) as prev_dt
from product_shipping as c
join product_shipping as p
on c.product_id = p.product_id
and c.deal_dt >= p.deal_dt
group by c.product_id
Cela produira des lignes pour lesquelles prev_dt = Deal_Dt, dans le cas où il n'y a pas d'enregistrement préalable.
Joignez-vous à ce que ce soit, saupoudrer WHERE
comme vous le souhaitez.
Tout d'abord, essayez de maintenir un identifiant de commande. Cela agira comme clé primaire et cela est logique que chaque commande devrait avoir un identifiant et cela identifiera de manière unique chaque nouvelle commande, même si le produit commandé est identique.
De plus, chaque produit possède un code de produit unique ou un numéro de série.
Je vous suggère de faire une clé primaire à l'aide de deux colonnes (orderid, produitsManNumber)
Alter table produit_shipping Ajouter une colonne commande_id varchar (10), code produit varchar (10));
Alter Tableau Product_Shipping Ajouter une contrainte PM_KEY Touche principale (Orderid, ProduitsAlnumber)
Maintenant, lorsqu'un produit est renvoyé, utilisez la commande et mal dans la date d'annulation, etc.
De plus, lorsque le produit est réorganisé, vous pouvez ajouter une nouvelle ligne avec un nouvel identifiant de commande et le même numéro de série.
Cela aidera à suivre l'historique des commandes d'un élément particulier, qui a tous commandé (numéro de série) et vous pouvez également ajouter une date d'annulation ou d'expédition.
Cela rend la récupération et la maintenance des données faciles.