1
votes

Comment utiliser MAX à partir d'une seule colonne à partir d'une seule table tout en interrogeant plusieurs colonnes à partir de plusieurs tables

J'ai donc reçu une demande de données de la part d'un membre de mon entreprise. Cette demande de données nécessite une requête SQL de plusieurs colonnes à partir de plusieurs tables MAIS ne peut être que l'incident le plus récent d'une colonne d'une de ces tables. Voici le kicker ... chaque table a une seule colonne qu'elle partage avec une autre table. Donc, pour obtenir ce "rapport", je dois le faire morceau par morceau.

Voici à quoi ressemblait ma requête initiale avant de réaliser que je n'ai besoin que de la mise à jour la plus récente de l'une des tables:

Description|Price   |ID       |DescriptionB   |date     |DescriptionC
---------------------------------------------------------------------
Computer   |300     |554      |7% Off         |9/1/2019 |Includes CPU
Computer   |300     |554      |7% Off         |9/1/2019 |Includes DOG
Computer   |300     |554      |7% Off         |9/1/2019 |Includes CAT 
Printer    |75      |801      |1% Off         |1/3/2019 |Includes DOS
Printer    |75      |801      |1% Off         |1/3/2019 |Includes PIG
Printer    |75      |801      |1% Off         |1/3/2019 |Includes RAT

J'ai réalisé que le "c.date" ci-dessus n'a besoin d'afficher que la date la plus récente pour chaque ID / DescriptionC unique.

Voici un exemple de résultat de la requête initiale:

Description|Price   |ID       |DescriptionB   |date     |DescriptionC
---------------------------------------------------------------------
Computer   |300     |554      |7% Off         |9/1/2019 |Includes CAT

Voici le résultat de la requête de Laurenz ci-dessous:

Description|Price   |ID       |DescriptionB   |date     |DescriptionC
---------------------------------------------------------------------
Computer   |300     |554      |5% Off         |3/2/2010 |Includes CPU
Computer   |300     |554      |5% Off         |3/2/2010 |Includes DOG
Computer   |300     |554      |5% Off         |3/2/2010 |Includes CAT 
Computer   |300     |554      |9% Off         |4/3/2011 |Includes CPU
Computer   |300     |554      |9% Off         |4/3/2011 |Includes DOG
Computer   |300     |554      |9% Off         |4/3/2011 |Includes CAT 
Computer   |300     |554      |7% Off         |9/1/2019 |Includes CPU
Computer   |300     |554      |7% Off         |9/1/2019 |Includes DOG
Computer   |300     |554      |7% Off         |9/1/2019 |Includes CAT 
Printer    |75      |801      |3% Off         |6/3/2012 |Includes DOS
Printer    |75      |801      |3% Off         |6/3/2012 |Includes PIG
Printer    |75      |801      |3% Off         |6/3/2012 |Includes RAT
Printer    |75      |801      |9% Off         |8/3/2013 |Includes DOS
Printer    |75      |801      |9% Off         |8/3/2013 |Includes PIG
Printer    |75      |801      |9% Off         |8/3/2013 |Includes RAT
Printer    |75      |801      |1% Off         |1/3/2019 |Includes DOS
Printer    |75      |801      |1% Off         |1/3/2019 |Includes PIG
Printer    |75      |801      |1% Off         |1/3/2019 |Includes RAT

... proche mais pas encore tout à fait là.

Résultat souhaité:

SELECT a.description  AS "Description", 
       a.pricing      AS "Price", 
       b.id           AS "ID", 
       c.descriptionb AS "DescriptionB", 
       c.date         AS "date", 
       d.descriptionc AS "DescriptionC" 
FROM   database.table1 a, 
       database.table2 b, 
       database.table3 c, 
       database.table4 d 
WHERE  a.description = b.descriptive_info 
       AND b.id = c.comp_id 
       AND c.descriptionb = d.long_description
       AND d.id_for_a = a.id
       AND a.company IN ( '000', '001', '002', '003', '004' ) 
       AND b.expdate >= Now()

Comme vous pouvez le voir, il y en a plusieurs les dates pour le «même produit», les produits en double avec des descriptions variables, etc. Je ne veux essentiellement que les lignes avec la «date» la plus récente pour chaque ID / DescriptionC unique. J'espère que c'est un peu plus facile à comprendre que mon article d'origine.

BTW, ce sont des exemples simplifiés car je ne veux pas avoir d'ennuis avec mon entreprise, mais la requête et les concepts sont les mêmes. Si vous pouvez imaginer plusieurs produits avec de nombreuses instances de chaque produit plusieurs fois, vous pouvez imaginer la taille de l'ensemble de données. Je ne me soucie que de l'instance la plus récente de chaque ID / DescriptionC unique.


3 commentaires

Quelques lignes de données et le résultat attendu correspondant nous aideraient probablement à fournir une réponse plus précise.


Vous n'avez donc besoin que de la dernière ligne de quels groupes? Comment voyez-vous quelle ligne est plus récente qu'une autre? Peut-être que montrer tous les champs de toutes les tables pourrait aider


Copie possible de Sélectionnez la première ligne de chaque groupe GROUP BY?


3 Réponses :


4
votes

Je comprends que, parmi les résultats de la requête actuelle, vous voulez simplement sélectionner celui qui a la valeur maximale sur c.date .

Une solution serait de transformer la requête existante en sous-requête, et d'utiliser ROW_NUMBER () pour classer les enregistrements en descendant c.date . Ensuite, la requête externe peut simplement filtrer sur l'enregistrement le mieux classé.

Requête:

SELECT *
FROM (
    SELECT 
        a.description  AS "Description", 
        a.pricing      AS "Price", 
        b.string       AS "String", 
        c.description  AS "Description", 
        c.date         AS "date", 
        d.descriptionb AS "DescriptionB",
        ROW_NUMBER() OVER (ORDER BY c.date DESC) AS rn
    FROM
       database.table1 a 
       INNER JOIN database.table2 b ON a.id = b.table1_id 
       INNER JOIN database.table3 c ON b.element = c.table2_element AND b.expdate >= Now()
       INNER JOIN database.table4 d ON c.value = d.table3_value 
    WHERE 
        a.company IN ( '000', '001', '002', '003', '004' ) 
) x WHERE rn = 1;

PS:

  • préfère toujours les jointures explicites au lieu des jointures implicites à l'ancienne; J'ai modifié la requête initiale en conséquence

  • si vous avez besoin de la date maximum par partition (ce qui n'est pas évident à dire sans voir des exemples de données), il vous suffit d'ajouter une clause PARTITION BY au ROW_NUMBER () fonction.


3 commentaires

Génial, cela a supprimé l'erreur, cependant, maintenant il n'aime pas l'avant-dernière clause "WHERE": ERROR: erreur de syntaxe à ou près de "WHERE" Voici un extrait de la requête ACTUAL beaucoup plus grande tout ce qui entoure "WHERE "instruction: INNER JOIN viper_logical_1.promotion_relatedmarketitems i ON i.element = b.externalid WHERE a.externalid IN ('5957962', '2882541')) x WHERE rn = 1 LINE 35: WHERE


@ user2079024: eh bien, il est difficile de dire ce qui ne va pas dans votre requête réelle ... Une chose que vous pouvez faire est d’essayer de limiter le problème: lancez d’abord la sous-requête et voyez si cela fonctionne, puis exécutez toute la requête.


D'accord ... donc cette requête est proche mais pas encore tout à fait là. J'ai mis à jour ma description originale du problème, les résultats et les résultats souhaités. J'espère que cela rendra les choses un peu plus claires quant à ce que je tente d'accomplir. Encore une fois, toute aide supplémentaire serait grandement appréciée!



2
votes

Le sql suivant peut être utilisé pour résoudre la question:

SELECT *
FROM (
    SELECT 
        a.description  AS "Description",

        a.pricing      AS "Price", 
        b.string       AS "String", 
        c.description  AS "Description", 
        c.date         AS "date", 
        d.descriptionb AS "DescriptionB",
        ROW_NUMBER() OVER (ORDER BY c.date DESC PARTITION BY B.ID ) AS rn
    FROM
       database.table1 a 
       INNER JOIN database.table2 b ON a.id = b.table1_id 
       INNER JOIN database.table3 c ON b.element = c.table2_element AND b.expdate >= Now()
       INNER JOIN database.table4 d ON c.value = d.table3_value 
    WHERE 
        a.company IN ( '000', '001', '002', '003', '004' ) 
) x WHERE rn = 1;


0 commentaires

1
votes

Merci beaucoup à tous. La réponse de Hal McGee était fondamentalement correcte! J'ai juste dû peaufiner certaines choses. Voici un exemple de la requête complète que j'ai fini par utiliser et qui fonctionnait car j'en avais besoin pour:

SELECT *
FROM (
    SELECT 
        a.description  AS "Description",
        a.pricing      AS "Price", 
        b.string       AS "String", 
        c.description  AS "Description", 
        c.date         AS "date", 
        d.descriptionb AS "DescriptionB",
        ROW_NUMBER() OVER (PARTITION BY d.descriptionc, b.id ORDER BY c.date DESC ) AS rn
    FROM
       database.table1 a 
       INNER JOIN database.table2 b ON a.id = b.table1_id 
       INNER JOIN database.table3 c ON b.element = c.table2_element AND b.expdate >= Now()
       INNER JOIN database.table4 d ON c.value = d.table3_value 
    WHERE 
        a.company IN ( '000', '001', '002', '003', '004' ) 
) x WHERE rn = 1;


0 commentaires