Pergunta

Eu tenho a seguinte consulta:

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;

O problema é que a mesa "EsnsSalesOrderItems" pode ter o mesmo EsnId em diferentes entradas.Quero restringir a consulta para obter apenas a última entrada "EsnsSalesOrderItems" isso tem o mesmo "EsnId".

Por "última" entrada quero dizer o seguinte:

Aquele que aparece por último na tabela "EsnsSalesOrderItems".Então por exemplo se "EsnsSalesOrderItems" tem duas entradas com "EsnId" = 6 e "createdAt" = '2012-06-19' e '2012-07-19' respectivamente, só deveria me dar a entrada de '2012-07-19'.

Foi útil?

Solução

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;

Sua consulta na pergunta possui uma agregação ilegal sobre outra agregação:

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

Simplificado e convertido para sintaxe legal:

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

Mas você realmente quer multiplicar pela contagem por grupo?

Eu recupero a única linha por grupo em "EsnsSalesOrderItems" com DISTINCT ON.Explicação detalhada:

Também adicionei aliases de tabela e formatação para tornar a consulta mais fácil de analisar para olhos humanos.Se você pudesse evite o caso do camelo, você pode se livrar de todas as aspas duplas turvando a visão.

Outras dicas

Algo como:

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

isso selecionará o mais recente "EsnId" de "EsnsSalesOrderItems" com base na coluna creation_date.Como você não postou a estrutura das suas tabelas, tive que "inventar" um nome de coluna.Você pode usar qualquer coluna que permita definir uma ordem nas linhas que mais lhe convier.

Mas lembre-se que o conceito de "última linha" só é válido se você especificar uma ordem ou as linhas.Uma tabela como tal não é ordenada, nem o resultado de uma consulta a menos que você especifica um order by

Necromante porque as respostas estão desatualizadas.
Aproveite o LATERAL palavra-chave introduzida em PG 9.3

Esquerda | à direita | junção interna LATERAL

Vou explicar com um exemplo:
Supondo que você tenha uma tabela "Contatos".
Agora os contatos possuem unidades organizacionais.
Eles podem ter uma UO por vez, mas N UOs em N momentos.

Agora, se você precisar consultar contatos e UO em um período de tempo (não uma data de relatório, mas um intervalo de datas), você poderia aumentar N vezes a contagem de registros se apenas fizesse uma junção à esquerda.
Então, para exibir a UO, você precisa apenas juntar a primeira UO de cada contato (onde o que deve ser o primeiro é um critério arbitrário - ao pegar o último valor, por exemplo, isso é apenas outra maneira de dizer o primeiro valor quando classificado por ordem decrescente de data).

No SQL-server, você usaria cross-apply (ou melhor, OUTER APPLY, já que precisamos de uma junção à esquerda), que invocará uma função com valor de tabela em cada linha que ela tiver que ingressar.

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 

No PostgreSQL, a partir da versão 9.3, você também pode fazer isso - basta usar o LATERAL palavra-chave para conseguir o mesmo:

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 

Tente usar uma subconsulta na sua cláusula ON.Um exemplo abstrato:

SELECT 
    *
FROM table1
JOIN table2 ON table2.id = (
    SELECT id FROM table2 WHERE table2.table1_id = table1.id LIMIT 1
)
WHERE 
    ...
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top