Domanda

Ho la seguente query:

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;
.

Il problema è che la tabella "EsnsSalesOrderItems" può avere lo stesso EsnId in diverse voci.Voglio limitare la query per estrarre solo l'ultima voce in "EsnsSalesOrderItems" che ha lo stesso "EsnId".

Per "ultima" voce intendo quanto segue:

Quello che appare per ultimo nella tabella "EsnsSalesOrderItems".Quindi, ad esempio, se "EsnsSalesOrderItems" ha due voci con "EsnId" = 6 e "createdAt" = '2012-06-19' e '2012-07-19' rispettivamente, dovrebbe darmi solo la voce da '2012-07-19'.

È stato utile?

Soluzione

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;
.

La tua query nella domanda ha un aggregato illegale su un altro aggregato:

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

Semplificato e convertito in sintassi legale:

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

Ma vuoi davvero moltiplicarsi con il conteggio per gruppo?

I Recupera la singola riga per gruppo in "EsnsSalesOrderItems" con DISTINCT ON .Spiegazione dettagliata:

Altri suggerimenti

Qualcosa come:

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
.

Selezionerà l'ultima "EsnId" in base a "EsnsSalesOrderItems"tagCode basata sulla colonna creation_date. Come non hai pubblicato la struttura delle tabelle, ho dovuto" inventare "un nome di colonna. Puoi usare qualsiasi colonna che ti permette di definireUn ordine sulle righe che ti si addice.

Ma ricorda che il concetto di "ultima riga" è valido solo se si specifica un ordine o le righe.Una tabella come tale non viene ordinata, né è il risultato di una query a meno che si specifica un order by

Necromancing perché le risposte sono obsolete.
. Approfitta della parola chiave LATERAL introdotta in PG 9.3

Sinistra | Destra |. Iscriviti interni Laterale

Spiegherò con un esempio:
Supponendo che tu abbia un tavolo "contatti".
. Ora i contatti hanno unità organizzative.
Possono avere uno ou in un punto nel tempo, ma n ous a n punti nel tempo.

Ora, se devi interrogare contatti e in un periodo di tempo (non una data di riferimento, ma un intervallo di date), è possibile che n-fold aumenta il conteggio dei record se hai appena fatto un Iscriviti a sinistra.
. Quindi, per visualizzare l'OU, è necessario solo unirti al primo ou per ogni contatto (dove quale sarà il primo è un criterio arbitrario - quando si prende l'ultimo valore, ad esempio, questo è solo un altro modo per dire il primo valore quando ordinato Discendente l'ordine della data).

In SQL-Server, si userebbe a cross-application (o uter esterno si applica perché abbiamo bisogno di un join sinistro), che invocherà una funzione di valore a tavola su ogni riga che deve aderire.

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 
.

in PostgreSQL, A partire dalla versione 9.3, Puoi farlo, utilizzare anche la parola chiave LATERAL per ottenere lo stesso:

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 
.

Prova a utilizzare una sottoquery nella tua clausola sulla clausola.Un esempio astratto:

SELECT 
    *
FROM table1
JOIN table2 ON table2.id = (
    SELECT id FROM table2 WHERE table2.table1_id = table1.id LIMIT 1
)
WHERE 
    ...
.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top