我有一个PSQL查询,左边的AND参数在下面的另一个表检查表示例中加入。
发票
id | account | invoice_date | reference | total_amount | status
-----+---------+-------------------------+-----------+--------------+--------
164 | 100 | 2016-08-03 03:05:08.996 | 161 | 2000.00 |
165 | 100 | 2016-08-03 21:42:07.865 | 164 | 0 |
167 | 100 | 2016-08-03 22:56:41.731 | 166 | 100.00 |
168 | 100 | 1970-01-01 00:33:20 | 161 | 200 |
169 | 100 | 2016-08-08 00:00:00 | 161 | 200 |
Invoice_items
id | invoice | invoice_item_type | product | quantity | unit_price | reference | amount
-----+---------+-------------------+---------+----------+------------+-----------+---------
143 | 164 | 1 | 6 | | | 161 | 2000.00
144 | 165 | 1 | 11 | | | 164 | 0
145 | 167 | 1 | 8 | | | 166 | 100.00
还有另一个表PRODUCTS,但唯一相关的字段是id
这是我的查询
select products.id, sum(invoice_items.amount) as total_revenue
from products
left join invoice_items on invoice_items.product = products.id
left join invoices on invoice_items.invoice = invoices.id
and invoices.invoice_date= current_date
group by products.id;
我需要查询的内容是列出所有产品ID,并在total_revenue列中,列出产品的销售总额(在invoice_items表中添加'amount',其中'product'字段类似)为当天(在INVOICES表中找到)。但是当我运行此查询时,它会列出产品的所有total_amounts。我错过了什么?
示例输出。 8,6和11必须为空
id | total_revenue
-----+---------------
125 |
154 |
119 |
129 |
8 | 100.00
112 |
5 |
132 |
104 |
113 |
143 |
152 |
121 |
127 |
165 |
139 |
146 |
15 |
2 |
147 |
149 |
166 |
169 |
13 |
106 |
122 |
9 |
11 | 0
110 |
120 |
130 |
155 |
134 |
136 |
101 |
168 |
131 |
157 |
161 |
103 |
150 |
159 |
107 |
108 |
145 |
4 |
12 |
158 |
167 |
138 |
162 |
100 |
156 |
163 |
124 |
123 |
109 |
153 |
102 |
105 |
151 |
116 |
133 |
140 |
160 |
148 |
126 |
141 |
7 |
118 |
10 |
164 |
128 |
14 |
144 |
135 |
1 |
6 | 2000.00
3 |
137 |
117 |
142 |
111 |
答案 0 :(得分:0)
您将获得大量NULL值,这似乎是基于您的查询所预期的。
这似乎是一个“内部”连接类型的问题而不是“左”连接。左连接将保留结果集中没有产品发票的所有实例。
您还可以将关于“DATE”的整个查询移动到having子句中(就个人而言,我更喜欢WHERE /中的子查询,因为我发现逻辑更清晰):
SELECT products.id, SUM(invoice_items.amount) AS total_revenue
FROM products
INNER JOIN invoice_items ON invoice_items.product = products.id
HAVING EXISTS (SELECT 1 FROM invoices WHERE invoice_items.invoice = invoices.id
AND invoices.invoice_date= current_date)
GROUP BY products.id;
答案 1 :(得分:0)
日期约束只过滤掉发票表中的记录,而您还需要它来过滤出invoice_items表中的记录 - 但它没有这样做,因为它们都是左连接。派生表将轻松解决此问题,并提供您想要的结果。我还添加了一些表别名,以简洁和可读。
像这样:
SELECT
p.id, SUM(inv.amount) AS total_revenue
FROM
products p LEFT JOIN
(SELECT
ii.product, i.invoice_date, ii.amount
FROM
invoice_items ii JOIN
invoices i ON
ii.invoice = i.id) inv ON
inv.product = p.id AND
inv.invoice_date= current_date
GROUP BY p.id;
答案 2 :(得分:0)
我明白了。具有所需结果的较小样本数据将有所帮助。
问题解释起来有点复杂。无论日期如何,left join
都会保留所有产品和发票。最终加入invoices
会引入仅在当前日期匹配的发票。但是,因为您在第二个表上进行求和,所以每个匹配的行都会出现一次(即使当天没有发票项目),它也会出现在您的结果中。
解决方案:使用case
语句确定invoice
项目表中是否存在匹配项:
select p.id,
sum(ii.amount * (case when i.id is not null then 1 end)) as total_revenue
from products p left join
invoice_items ii
on ii.product = p.id left join
invoices i
on ii.invoice = i.id and i.invoice_date = current_date
group by p.id;
我还怀疑该日期的正确条件是:
on ii.invoice = i.id and i.invoice_date >= current_date and
i.invoice_date < current_date + interval '1 day'
此外,将此作为子查询编写可以保存外部聚合,还应该解决问题:
select p.*,
(select sum(ii.amount)
from invoice_items ii join
invoices i
on ii.invoice = i.id and i.invoice_date >= current_date and
i.invoice_date < current_date + interval '1 day'
where ii.product = p.id
) as total_revenue
from products p;