-
11-12-2019 - |
题
我有以下查询:
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
关键字介绍 PG9.3
左|右/内连接 横向;横向
我会用一个例子来解释:
假设你有一个表"联系人"。
现在联系人有组织单位。
他们可以在一个时间点有一个OU,但在N个时间点有N个Ou。
现在,如果您必须查询联系人和OU 在一个时间段 (不是一个报告日期,而是一个日期范围),如果你只是做了一个左连接,你可以n倍增加记录计数。
因此,要显示OU,您只需要为每个联系人加入第一个OU(首先是一个任意标准-例如,当采用最后一个值时,这只是按日期降序排序时第一个值的另一种方式)。
在SQL-server中,您将使用交叉应用(或者更确切地说,外部应用,因为我们需要左连接),这将在它必须连接的每一行上调用表值函数。
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
...