mysql子查询理解

时间:2014-08-09 22:02:19

标签: mysql sql

我正在尝试查找所有在sales_item_taxes表中都有条目的sale_id,但在sales_items表中没有相应的条目。

mysql> describe phppos_sales_items_taxes;
+------------+---------------+------+-----+---------+-------+
| Field      | Type          | Null | Key | Default | Extra |
+------------+---------------+------+-----+---------+-------+
| sale_id    | int(10)       | NO   | PRI | NULL    |       |
| item_id    | int(10)       | NO   | PRI | NULL    |       |
| line       | int(3)        | NO   | PRI | 0       |       |
| name       | varchar(255)  | NO   | PRI | NULL    |       |
| percent    | decimal(15,3) | NO   | PRI | NULL    |       |
| cumulative | int(1)        | NO   |     | 0       |       |
+------------+---------------+------+-----+---------+-------+
6 rows in set (0.01 sec)

mysql> describe phppos_sales_items;
+--------------------+----------------+------+-----+--------------+-------+
| Field              | Type           | Null | Key | Default      | Extra |
+--------------------+----------------+------+-----+--------------+-------+
| sale_id            | int(10)        | NO   | PRI | 0            |       |
| item_id            | int(10)        | NO   | PRI | 0            |       |
| description        | varchar(255)   | YES  |     | NULL         |       |
| serialnumber       | varchar(255)   | YES  |     | NULL         |       |
| line               | int(3)         | NO   | PRI | 0            |       |
| quantity_purchased | decimal(23,10) | NO   |     | 0.0000000000 |       |
| item_cost_price    | decimal(23,10) | NO   |     | NULL         |       |
| item_unit_price    | decimal(23,10) | NO   |     | NULL         |       |
| discount_percent   | int(11)        | NO   |     | 0            |       |
+--------------------+----------------+------+-----+--------------+-------+
9 rows in set (0.00 sec)

mysql> 

提议的查询:

SELECT DISTINCT sale_id 
FROM phppos_sales_items_taxes 
WHERE item_id NOT IN
(SELECT item_id FROM phppos_sales_items WHERE sale_id = phppos_sales_items_taxes.sale_id)

我感到困惑的部分是子查询。查询似乎按预期工作,但我不理解子查询部分。它如何看待每次销售?

例如,如果我有以下数据:

mysql> select * from phppos_sales;
+---------------------+-------------+-------------+---------+-------------------------+---------+--------------------+-----------+-----------+------------+---------+-----------+-----------------------+-------------+---------+
| sale_time           | customer_id | employee_id | comment | show_comment_on_receipt | sale_id | payment_type       | cc_ref_no | auth_code | deleted_by | deleted | suspended | store_account_payment | location_id | tier_id |
+---------------------+-------------+-------------+---------+-------------------------+---------+--------------------+-----------+-----------+------------+---------+-----------+-----------------------+-------------+---------+
| 2014-08-09 17:53:38 |        NULL |           1 |         |                       0 |       1 | Cash: $12.96<br /> |           |           |       NULL |       0 |         0 |                     0 |           1 |    NULL |
| 2014-08-09 17:56:59 |        NULL |           1 |         |                       0 |       2 | Cash: $12.96<br /> |           |           |       NULL |       0 |         0 |                     0 |           1 |    NULL |
+---------------------+-------------+-------------+---------+-------------------------+---------+--------------------+-----------+-----------+------------+---------+-----------+-----------------------+-------------+---------+

mysql> select * from phppos_sales_items;
+---------+---------+-------------+--------------+------+--------------------+-----------------+-----------------+------------------+
| sale_id | item_id | description | serialnumber | line | quantity_purchased | item_cost_price | item_unit_price | discount_percent |
+---------+---------+-------------+--------------+------+--------------------+-----------------+-----------------+------------------+
|       2 |       1 |             |              |    1 |       1.0000000000 |   10.0000000000 |   12.0000000000 |                0 |
+---------+---------+-------------+--------------+------+--------------------+-----------------+-----------------+------------------+
1 row in set (0.00 sec)


mysql> select * from phppos_sales_items_taxes;
+---------+---------+------+-----------+---------+------------+
| sale_id | item_id | line | name      | percent | cumulative |
+---------+---------+------+-----------+---------+------------+
|       1 |       1 |    1 | Sales Tax |   8.000 |          0 |
|       2 |       1 |    1 | Sales Tax |   8.000 |          0 |
+---------+---------+------+-----------+---------+------------+
2 rows in set (0.00 sec)

当我运行下面的查询时,它确实找到了sale_id 1.但子查询如何知道正确过滤。我想我不理解子查询是如何工作的。

mysql>     SELECT DISTINCT sale_id 
    ->     FROM phppos_sales_items_taxes 
    ->     WHERE item_id NOT IN
    ->     (SELECT item_id FROM phppos_sales_items WHERE sale_id = phppos_sales_items_taxes.sale_id)
    -> ;
+---------+
| sale_id |
+---------+
|       1 |
+---------+
1 row in set (0.00 sec)

4 个答案:

答案 0 :(得分:2)

Duffy356链接到SQL-Joins是好的,但有时看到你自己的数据可能有时更有意义......

首先,你的查询书面显然对于引擎来说非常昂贵。它如何知道要包含的内容是因为它正在执行相关的子查询 - 这意味着对于sales_items_taxes表中的每条记录,它正在对sales_items表运行查询,该表返回所述sale_id的每个可能项。然后它返回主查询并将其与sales_items_taxes表进行比较。如果找不到,则允许将sale_id包含在结果集中。然后它转到sales_items_taxes表中的下一条记录。

(您的查询已重新格式化以提高可读性)

SELECT DISTINCT 
      sale_id 
   FROM 
      phppos_sales_items_taxes
   WHERE 
      item_id NOT IN ( SELECT item_id 
                          FROM phppos_sales_items 
                          WHERE sale_id = phppos_sales_items_taxes.sale_id)

现在,想一想。您有1件特卖,包含100件商品。它运行相关的子查询100次。现在使用1,000个销售ID条目执行此操作,但每个条目都有很多项,很快就会变得昂贵。

更好的选择是利用数据库并进行左连接。索引直接与LEFT JOIN(或内部联接)一起使用,并由引擎优化。此外,请注意我正在为表使用“别名”并限定别名以提高可读性。从您的销售项目税收表开始(您正在寻找额外的条目)是基础。现在,在sales_id和item_id的两个关键组件上左连接此销售项目表。我建议每个表都有一个索引ON(sale_id,item_id)来匹配这里的连接条件。

SELECT DISTINCT 
      sti.sale_id 
   FROM 
      phppos_sales_items_taxes sti
         LEFT JOIN phppos_sales_items si
            ON sti.sale_id = si.sale_id
            AND sti.item_id = si.item_id
   WHERE 
      si.sale_id IS NULL

所以,从这里开始,想一想每张桌子是彼此并排排列的,而你所得到的只是左边的那些(销售物品税)那些没有条目的右侧(sales_items)。

答案 1 :(得分:1)

使用联接可以解决您的问题。

阅读以下关于SQL-Joins的文章,并考虑一下您的问题 - &gt;你将能够解决它;)

IN子句不是最佳解决方案,因为某些数据库对其中包含的参数数量有限制。

答案 2 :(得分:0)

你真正想要的是:

SELECT DISTINCT sale_id 
FROM phppos_sales_items_taxes 
WHERE sale_id NOT IN
(SELECT sale_id FROM phppos_sales_items)

WHERE field NOT IN (SELECT field FROM anothertable WHERE ...)是一个完美的查询结构。

答案 3 :(得分:0)

您的原始查询:

SELECT DISTINCT sale_id 来自phppos_sales_items_taxes WHERE item_id NOT IN (SELECT item_id FROM phppos_sales_items WHERE sale_id = phppos_sales_items_taxes.sale_id)

在这里,您将从phppos_sales_items表中提取所有item_id,其中sale_id与tax表匹配,并从最终结果中删除这些item_id。

您也可以通过其他方式获得相同的结果,这可能很容易理解。

  1. 在多个列中使用IN查询: 选择不同的sales_id 来自sales_item_taxes where(sale_id,item_id)不在(选择sale_id,来自phppos_sales_items的item_id)
  2. - 这种形式的查询易于阅读和理解。性能可能不适合大型表。

    1. 存在/不存在格式: 选择不同的sales_id 来自sales_item_taxes t1 哪里不存在(从phppos_sales_items t2中选择&#39; 1&#39; 其中t2.sale_id = t1.sale_id 和t2.item_id = t1.item_id )
    2. 我也会提出与&#39; bwperrin&#39;相同的解决方案。做了 - 不知道为什么你没有通过运行查询得到任何输出。如果您的标准是在sale_id上​​过滤 - 这是最佳解决方案。但看起来您正在使用(sale_id,item_id)作为识别销售记录的方法。确保您的表结构有意义。