我正在使用以下查询从3个不同的表中选择数据。 tbl_invoices和tbl_clients具有唯一记录。每个tbl_invoices记录都有多个tbl_invoice_entries记录:
$HOME/.bashrc
这将返回tbl_invoice_entries中的所有记录。如何更改查询以仅返回每个tbl_invoices记录的第一个tbl_invoice_entries记录。
以下是表格:
tbl_clients
$query = 'SELECT T1.*, T2.*, T3.*
FROM tbl_invoices T1
LEFT JOIN tbl_invoice_entries T2
ON T1.number = T2.invoice_number
LEFT JOIN tbl_clients T3
ON T1.client = T3.client_id
WHERE date_format(date, '%Y') = ".$_POST['year']." AND date_format(date, '%c') = ".$_POST['month']." ORDER BY date, number ASC'
$stmt = $conn->prepare($query)
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
tbl_invoices
+----+-----------+----------+
| id | firstname | lastname |
+----+-----------+----------+
| 1 | John | Doe |
| 2 | Jane | Doe |
+----+-----------+----------+
tbl_invoice_entries
+----+--------+--------+------------+
| id | number | client | date |
+----+--------+--------+------------+
| 1 | 14 | 1 | 2015-07-14 |
| 1 | 15 | 2 | 2015-07-14 |
+----+--------+--------+------------+
所以我正在寻找的结果是:
John Doe 14 Fish 2015-07-14
Jane Doe 15蔬菜2015-07-14
感谢您的帮助!
答案 0 :(得分:2)
通过将invoice_entries表直接链接到发票编号而不是第一个条目的ID,您可以实现您想要的目标:
SELECT firstname,lastname,number,product,date
FROM tbl_invoices T1
LEFT JOIN tbl_invoice_entries T2
ON T2.id =(select min(id) from tbl_invoice_entries
where invoice_number=number)
LEFT JOIN tbl_clients T3
ON T1.client = T3.id
WHERE ...
答案 1 :(得分:1)
您需要通过第一行告诉RDBMS您的意图。元组中没有自然顺序。如果你想要给出相同invoice_number 的最低ID的元组,那么它将需要另一个查询
SELECT tbl1.* FROM tbl_invoice_entries AS tbl1
JOIN ( SELECT MIN(id) AS id, invoice_number FROM tbl_invoice_entries
GROUP BY invoice_number ) AS tbl2
USING (id);
上述查询相当于tbl_invoice_entries
,但只有每个发票编号的最低ID。您可以将其作为VIEW(实际上是两个,因为您不能在VIEW中使用子查询):
CREATE VIEW tbl_invoice_entries_firstnumber AS
SELECT MIN(id) AS id, invoice_number
FROM tbl_invoice_entries
GROUP BY invoice_number;
CREATE VIEW tbl_invoice_entries_first AS
SELECT tbl1.* FROM tbl_invoice_entries AS tbl1
JOIN tbl_invoice_entries_firstnumber
USING (id);
之后,您可以在当前查询中使用tbl_invoice_entries_first
代替tbl_invoice_entries
。
请注意,视图是动态,因此它只是更复杂查询的简写。这意味着您当前的查询将变得更加复杂,需要更长的时间:
SELECT T1.*, T2.*, T3.*
FROM tbl_invoices AS T1
LEFT JOIN tbl_invoice_entries_first AS T2
ON T1.number = T2.invoice_number
LEFT JOIN tbl_clients AS T3
ON T1.client = T3.id; -- you have no client_id in T3
我已经设置了一个小提琴here。
或者你可以更多地修改你的查询,并在T2上添加一个JOIN条件,这样它只会再次获取最小ID - 或者你喜欢的任何排序条件:
SELECT T1.*, T2.*, T3.*
FROM tbl_invoices AS T1
LEFT JOIN tbl_invoice_entries AS T2
ON (
-- (( T1.number = T2.invoice_number AND )) --
T2.id = (
SELECT MIN(id) FROM tbl_invoice_entries
WHERE invoice_number = number
))
LEFT JOIN tbl_clients AS T3
ON T1.client = T3.id;
更新:对数字的检查已被注释掉(另请参阅@ cars10的解决方案),因为它由内部子查询继承。
最后,您可以在代码中执行此操作,即保存上一个元组的值并根据需要对查询进行排序;然后丢弃所有不需要的元组。如果每张发票的条目很少,这可能是值得的:
// pseudo code
if (prev.client == tuple.client)
and
(prev.invoice == tuple.invoice)
continue;
prev = tuple;
-- use tuple.