繁体   English   中英

如何仅在内部联接查询的第二个表中选择第一行

[英]How to select first row only in 2nd table of inner join query

我正在使用以下查询从3个不同的表中选择数据。 tbl_invoices和tbl_clients具有唯一记录。 每个tbl_invoices记录都有多个tbl_invoice_entries记录:

$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_invoice_entries中的所有记录。 我如何更改查询以仅返回每个tbl_invoices记录的第一个tbl_invoice_entries记录。

表格如下:

tbl_clients

+----+-----------+----------+
| id | firstname | lastname |
+----+-----------+----------+
|  1 | John      | Doe      |
|  2 | Jane      | Doe      |
+----+-----------+----------+

tbl_invoices

+----+--------+--------+------------+
| id | number | client |    date    |
+----+--------+--------+------------+
|  1 |     14 |      1 | 2015-07-14 |
|  1 |     15 |      2 | 2015-07-14 |
+----+--------+--------+------------+

tbl_invoice_entries

+----+----------------+------------+
| id | invoice_number |  produkt   |
+----+----------------+------------+
|  1 |             14 | Fish       |
|  2 |             14 | Bread      |
|  3 |             15 | Vegetables |
|  4 |             15 | Fruit      |
+----+----------------+------------+

所以我要寻找的结果是:

John Doe 14鱼2015-07-14

Jane Doe 15蔬菜2015-07-14

谢谢你的帮助!

通过不直接通过发票编号链接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 ...

您需要在第一行告诉RDBMS您打算做什么。 元组中没有自然顺序。 如果您希望给最低ID元组指定相同的invoice_number ,则将需要另一个查询

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

在这里摆了一个小提琴。

或者,您可以进一步修改查询,并在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.

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM