6

次のクエリがあります。

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"の 2 つのエントリがある場合、 からのエントリのみが表示されます。"EsnId" = 6"createdAt" = '2012-06-19''2012-07-19''2012-07-19'

4

4 に答える 4

16
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

しかし、本当にグループごとの数を掛けたいですか?

でグループごとに 1 つの行を取得"EsnsSalesOrderItems"しますDISTINCT ON。詳細な説明:

また、人間の目でクエリを解析しやすくするために、テーブルのエイリアスと書式設定も追加しました。キャメルケースを回避できれば、ビューを曇らせているすべての二重引用符を取り除くことができます。

于 2012-09-29T13:16:26.633 に答える
5

何かのようなもの:

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

于 2012-09-29T08:21:51.807 に答える
4

答えが古くなっているためネクロマンシング。PG 9.3で導入され
たキーワードを利用するLATERAL

左 | 左 | 右 | 内部 JOIN LATERAL

例を挙げて説明します
。「連絡先」というテーブルがあるとします。
現在、連絡先には組織単位があります。
ある時点で 1 つの OU を持つことができますが、N 時点では OU はありません。

ここで、ある期間(レポート日ではなく日付範囲) で連絡先と OU を照会する必要がある場合、左結合を行っただけで、レコード数を N 倍に増やすことができます。
そのため、OU を表示するには、連絡先ごとに最初の OU に参加する必要があります (ここで、最初にするものは任意の基準です。たとえば、最後の値を取得する場合は、並べ替えたときに最初の値を示す別の方法です)。日付の降順)。

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 

バージョン 9.3 以降のPostgreSQL では、これも実行できます。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 
于 2016-01-28T14:43:18.443 に答える
3

ON 句でサブクエリを使用してみてください。抽象的な例:

SELECT 
    *
FROM table1
JOIN table2 ON table2.id = (
    SELECT id FROM table2 WHERE table2.table1_id = table1.id LIMIT 1
)
WHERE 
    ...
于 2012-09-29T07:25:25.270 に答える