Вопрос

У меня есть следующий запрос:

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;

Проблема в том, что таблица "EsnsSalesOrderItems" может быть то же самое EsnId в разных записях.Я хочу ограничить запрос, чтобы получить только последнюю запись в "EsnsSalesOrderItems" у которого то же самое "EsnId".

Под «последней» записью я имею в виду следующее:

Тот, который появляется последним в таблице "EsnsSalesOrderItems".Так, например, если "EsnsSalesOrderItems" имеет две записи с "EsnId" = 6 и "createdAt" = '2012-06-19' и '2012-07-19' соответственно, он должен дать мне только запись из '2012-07-19'.

Это было полезно?

Решение

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;

Ваш запрос в вопросе содержит недопустимый агрегат по сравнению с другим агрегатом:

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

Упрощенный и преобразованный в допустимый синтаксис:

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

Но действительно ли вы хотите умножить число на группу?

Я получаю одну строку для каждой группы в "EsnsSalesOrderItems" с DISTINCT ON.Детальное объяснение:

Я также добавил псевдонимы таблиц и форматирование, чтобы упростить анализ запроса для человеческого глаза.Если бы ты мог избегайте верблюжьего случая, вы можете избавиться от всех двойных кавычек затуманивание зрения.

Другие советы

Что-то вроде:

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

это выберет самую последнюю "EsnId" от "EsnsSalesOrderItems" на основе столбца creation_date.Поскольку вы не опубликовали структуру своих таблиц, мне пришлось «придумывать» имя столбца.Вы можете использовать любой столбец, который позволяет вам определить подходящий вам порядок в строках.

Но помните, что концепция «последней строки» действительна только в том случае, если вы указываете порядок или строки.Таблица как таковая не упорядочена и не является результатом запроса. пока не вы указываете order by

Некромантия, потому что ответы устарели.
Воспользуйтесь LATERAL ключевое слово, введенное в PG 9.3

слева | справа | внутреннее соединение БОКОВОЙ

Поясню на примере:
Предположим, у вас есть таблица «Контакты».
Теперь у контактов есть организационные подразделения.
В определенный момент времени у них может быть одно подразделение, но в N моментов времени — N OU.

Теперь, если вам нужно запросить контакты и подразделение в период времени (не отчетная дата, а диапазон дат), вы можете увеличить количество записей в N раз, если просто выполните левое соединение.
Итак, чтобы отобразить подразделение, вам нужно просто присоединиться к первому подразделению для каждого контакта (где то, что должно быть первым, является произвольным критерием - например, при выборе последнего значения это просто еще один способ указать первое значение при сортировке). в порядке убывания даты).

В SQL-сервере вы должны использовать перекрестное применение (или, скорее, OUTER APPLY, поскольку нам нужно левое соединение), которое будет вызывать функцию с табличным значением для каждой строки, к которой она должна присоединиться.

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 

В PostgreSQL начиная с версии 9.3, вы тоже можете это сделать - просто используйте LATERAL ключевое слово для достижения того же:

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 

Попробуйте использовать подзапрос в предложении ON.Абстрактный пример:

SELECT 
    *
FROM table1
JOIN table2 ON table2.id = (
    SELECT id FROM table2 WHERE table2.table1_id = table1.id LIMIT 1
)
WHERE 
    ...
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top