Question

J'ai la requête suivante:

SELECT sum((select count(*) as itemCount) * "SalesOrderItems"."price") as amount, 'rma' as     
    "creditType", "Clients"."company" as "client", "Clients".id as "ClientId", "Rmas".* 
FROM "Rmas" JOIN "EsnsRmas" on("EsnsRmas"."RmaId" = "Rmas"."id") 
    JOIN "Esns" on ("Esns".id = "EsnsRmas"."EsnId") 
    JOIN "EsnsSalesOrderItems" on("EsnsSalesOrderItems"."EsnId" = "Esns"."id" ) 
    JOIN "SalesOrderItems" on("SalesOrderItems"."id" = "EsnsSalesOrderItems"."SalesOrderItemId") 
    JOIN "Clients" on("Clients"."id" = "Rmas"."ClientId" )
WHERE "Rmas"."credited"=false AND "Rmas"."verifyStatus" IS NOT null 
GROUP BY "Clients".id, "Rmas".id;

Le problème c'est que la table "EsnsSalesOrderItems" peut avoir le même EsnId dans les différentes entrées.Je veux restreindre la requête de tirer seulement la dernière entrée dans "EsnsSalesOrderItems" qui a le même "EsnId".

Par "dernier" entrée, je veux dire les éléments suivants:

Celui qui apparaît en dernier dans la table "EsnsSalesOrderItems".Ainsi, par exemple si "EsnsSalesOrderItems" a deux entrées avec "EsnId" = 6 et "createdAt" = '2012-06-19' et '2012-07-19' respectivement, il ne devrait me donner de l'entrée de '2012-07-19'.

Était-ce utile?

La solution

SELECT (count(*) * sum(s."price")) AS amount
     , 'rma'       AS "creditType"
     , c."company" AS "client"
     , c.id        AS "ClientId"
     , r.* 
FROM   "Rmas"            r
JOIN   "EsnsRmas"        er ON er."RmaId" = r."id"
JOIN   "Esns"            e  ON e.id = er."EsnId"
JOIN  (
   SELECT DISTINCT ON ("EsnId") *
   FROM   "EsnsSalesOrderItems"
   ORDER  BY "EsnId", "createdAt" DESC
   )                     es ON es."EsnId" = e."id"
JOIN   "SalesOrderItems" s  ON s."id" = es."SalesOrderItemId"
JOIN   "Clients"         c  ON c."id" = r."ClientId"
WHERE  r."credited" = FALSE
AND    r."verifyStatus" IS NOT NULL 
GROUP  BY c.id, r.id;

Votre requête dans la question illégale d'un ensemble plus un autre agrégat:

sum((select count(*) as itemCount) * "SalesOrderItems"."price") as amount

Simplifié et converti juridique de la syntaxe:

(count(*) * sum(s."price")) AS amount

Mais voulez-vous vraiment à se multiplier avec le comte par groupe?

- Je récupérer la ligne unique par groupe dans "EsnsSalesOrderItems" avec DISTINCT ON.Explication détaillée:

J'ai également ajouté des alias de table et mise en forme pour faire la requête plus facile à analyser pour les yeux humains.Si vous pouviez éviter de chameau cas, vous pourriez se débarrasser de tous les guillemets obscurcissement de la vue.

Autres conseils

Quelque chose comme:

join (
  select "EsnId", 
         row_number() over (partition by "EsnId" order by "createdAt" desc) as rn
  from "EsnsSalesOrderItems"
) t ON t."EsnId" = "Esns"."id" and rn = 1

cela permet de sélectionner la dernière "EsnId" à partir de "EsnsSalesOrderItems" basé sur la colonne creation_date.Comme vous n'avez pas de poste de la structure de vos tables, j'ai dû "inventer" un nom de colonne.Vous pouvez utiliser n'importe quelle colonne vous permet de définir un ordre sur les lignes qui vous convient.

Mais rappelez-vous le concept de la "dernière ligne" n'est valable que si vous spécifier une commande ou de l'lignes.Un tableau en tant que tel n'est pas ordonnée, ni le résultat d'une requête à moins que vous spécifiez un order by

Necromancing parce que les réponses sont obsolètes.
Profitez de l' LATERAL mot-clé introduit dans PG 9.3

gauche | droite | inner JOIN LATÉRALE

Je vais vous expliquer avec un exemple:
En supposant que vous avez une table "Contacts".
Maintenant, les contacts des unités organisationnelles.
Ils peuvent avoir une unité à un point dans le temps, mais N OUs N points dans le temps.

Maintenant, si vous avez une requête à des contacts et OU dans une période de temps (pas une date de rapport, mais une plage de dates), vous pourriez N multiplié par le nombre d'enregistrement si vous venez de faire un left join.
Ainsi, pour afficher l'unité d'organisation, vous avez juste besoin de se joindre à la première unité d'organisation pour chaque contact (où ce sera la première est un critère arbitraire - lors de la prise de la dernière valeur, par exemple, qui est juste une autre façon de dire que la première valeur lorsque triés par ordre décroissant d'ordre de date).

Dans SQL server, vous pouvez utiliser de la croix-appliquer (ou plutôt de l'EXTÉRIEUR, car nous avons besoin d'une jointure gauche), qui va appeler une fonction table sur chaque ligne il a de rejoindre.

SELECT * FROM T_Contacts 

--LEFT JOIN T_MAP_Contacts_Ref_OrganisationalUnit ON MAP_CTCOU_CT_UID = T_Contacts.CT_UID AND MAP_CTCOU_SoftDeleteStatus = 1 
--WHERE T_MAP_Contacts_Ref_OrganisationalUnit.MAP_CTCOU_UID IS NULL -- 989

-- CROSS APPLY -- = INNER JOIN 
OUTER APPLY    -- = LEFT JOIN 
(
    SELECT TOP 1 
         --MAP_CTCOU_UID    
         MAP_CTCOU_CT_UID   
        ,MAP_CTCOU_COU_UID  
        ,MAP_CTCOU_DateFrom 
        ,MAP_CTCOU_DateTo   
   FROM T_MAP_Contacts_Ref_OrganisationalUnit 
   WHERE MAP_CTCOU_SoftDeleteStatus = 1 
   AND MAP_CTCOU_CT_UID = T_Contacts.CT_UID 

    /*  
    AND 
    ( 
        (@in_DateFrom <= T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateTo) 
        AND 
        (@in_DateTo >= T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateFrom) 
    ) 
    */
   ORDER BY MAP_CTCOU_DateFrom 
) AS FirstOE 

Dans PostgreSQL, a partir de la version 9.3, vous pouvez aussi le faire - il suffit d'utiliser la LATERAL mot-clé pour obtenir le même:

SELECT * FROM T_Contacts 

--LEFT JOIN T_MAP_Contacts_Ref_OrganisationalUnit ON MAP_CTCOU_CT_UID = T_Contacts.CT_UID AND MAP_CTCOU_SoftDeleteStatus = 1 
--WHERE T_MAP_Contacts_Ref_OrganisationalUnit.MAP_CTCOU_UID IS NULL -- 989


LEFT JOIN LATERAL 
(
    SELECT 
         --MAP_CTCOU_UID    
         MAP_CTCOU_CT_UID   
        ,MAP_CTCOU_COU_UID  
        ,MAP_CTCOU_DateFrom 
        ,MAP_CTCOU_DateTo   
   FROM T_MAP_Contacts_Ref_OrganisationalUnit 
   WHERE MAP_CTCOU_SoftDeleteStatus = 1 
   AND MAP_CTCOU_CT_UID = T_Contacts.CT_UID 

    /*  
    AND 
    ( 
        (__in_DateFrom <= T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateTo) 
        AND 
        (__in_DateTo >= T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateFrom) 
    ) 
    */
   ORDER BY MAP_CTCOU_DateFrom 
   LIMIT 1 
) AS FirstOE 

Essayez d'utiliser une sous-requête dans votre clause.Un résumé exemple:

SELECT 
    *
FROM table1
JOIN table2 ON table2.id = (
    SELECT id FROM table2 WHERE table2.table1_id = table1.id LIMIT 1
)
WHERE 
    ...
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top