基于子查询的SQL查询。使用数据检索交易>阈

时间:2014-05-29 14:12:48

标签: mysql sql datetime subquery conditional-statements

我的db表称为事务,如下所示:

 Name |    Date (DateTime)   | Type |  Stock    | Volume | Price | Total
 Tom    2014-05-24 12:00:00    Sell   Barclays     100      2.2     220.0
 Bob    2014-04-13 15:00:00    Buy    Coca-Cola    10       12.0    120.0

varchar    DateTime           varchar varchar      int      float   float   

我最初的问题是从表中删除所有属于第一个事务晚于某个阈值的用户的事务。 我的疑问是:

DELETE FROM transactions WHERE name NOT IN (SELECT name FROM transactions2 WHERE date < CAST('2014-01-01 12:00:00.000' as DateTime));
Query OK, 35850 rows affected (3 hours 5 min 28.88 sec)

我认为这是一个糟糕的解决方案,我不得不复制表格以避免从我正在阅读的同一个表中删除,并且执行需要相当长的时间(对于包含~17万行的表,需要3个小时)< / p>

现在我正在尝试删除属于最新交易发生在特定阈值日期之前的用户的所有交易。

DELETE FROM transactions WHERE name IN (SELECT name FROM transactions HAVING max(date) < CAST('2015-01-01 12:00:00.000' as DateTime) );

可悲的是,子查询只找到一个结果:

SELECT name FROM transactions HAVING max(date) < CAST('2015-01-01 12:00:00.000' as DateTime)';

+------------+
| name       |
+------------+
| david      |
+------------+

我想因为max()函数我只得到一个结果。 我不是SQL的专家,但我很清楚我在集合和逻辑方面需要什么。 我很乐意就如何重写查询提出建议。

编辑: 这是一个包含架构和一些数据的sqlfiddle:http://sqlfiddle.com/#!2/389ede/2

我需要删除alex的所有条目,因为他的上次交易发生在某个阈值之前(比如2013年1月1日)。 不需要删除汤姆的交易,因为他的最新交易时间晚于2013年1月1日。

3 个答案:

答案 0 :(得分:1)

您的第一个查询可以表述为:`从之前不存在该用户的事务的事务中删除用户?这很容易转换为sql:

delete from transactions t1
where not exists (
    select 1 from transactions t2
    where t1.name = t2.name
      and t2.date < ?
)

mysql仍然不支持(AFAIK)从select中引用的表中删除,因此我们需要将其重写为:

delete t1.* 
from transactions t1
left join transactions t2
    on t1.name = t2.name
   and t2.date < ?
where t2.name is null

日期是一个保​​留字,所以你必须引用它。

您的第二个查询可以通过相同的方式解决,从事务中删除它在特定日期之后不存在的事务。我将它留作练习。

答案 1 :(得分:1)

Alvin这里是一个简化的场景,来自你的日期:

CREATE TABLE transactions 
(    id    int(11) NOT NULL AUTO_INCREMENT
,    name  varchar(30) NOT NULL
,    value datetime NOT NULL
,       PRIMARY KEY (id) ) ENGINE=InnoDB;

INSERT INTO transactions (name, value) VALUES ('alex',  '2011-01-01 12:00:00')
                                           ,  ('alex',  '2012-06-01 12:00:00');

让我们调查一下发生了什么:

SELECT t1.name as t1_name, t1.value as t1_value
     , t2.name as t2_name, t2.values as t2_value
FROM transactions t1
LEFT JOIN transactions t2
    ON t1.name = t2.name

T1_NAME     T1_VALUE    T2_NAME     T2_VALUE
alex    January, 01 2011 12:00:00+0000  alex    January, 01 2011 12:00:00+0000
alex    January, 01 2011 12:00:00+0000  alex    June, 01 2012 12:00:00+0000
alex    June, 01 2012 12:00:00+0000     alex    January, 01 2011 12:00:00+0000
alex    June, 01 2012 12:00:00+0000     alex    June, 01 2012 12:00:00+0000

即。 4行。如果我们现在添加连接谓词:

SELECT t1.name as t1_name, t1.value as t1_value
     , t2.name as t2_name, t2.values as t2_value
FROM transactions t1
LEFT JOIN transactions t2
    ON t1.name = t2.name    
   AND t2.value > CAST('2011-06-01 12:00.000' as DateTime)

这给我们留下了两行。如果我们将时间更改为2012-06-01 12:00.000&#39;由于左连接,我们仍有两行,但t2列将为空。

如果我们现在添加WHERE子句:

SELECT t1.name as t1_name, t1.value as t1_value
     , t2.name as t2_name, t2.values as t2_value
FROM transactions t1
LEFT JOIN transactions t2
    ON t1.name = t2.name    
   AND t2.value > CAST('2012-06-01 12:00.000' as DateTime)
WHERE t2.name is null;

我们还有两排。使用CAST(&#39; 2011-06-01 12:00.000&#39;作为DateTime),没有行。

请记住,构造等同于:

SELECT t1.name as t1_name, t1.value as t1_value
FROM transactions t1
WHERE NOT EXISTS (
    SELECT 1 FROM transactions t2
    WHERE t1.name = t2.name    
      AND t2.value > CAST('2012-06-01 12:00.000' as DateTime)
);

所以,如果它不存在值为&gt;的名称的行; &#39; 2012-06-01 12:00.000&#39;我们有一场比赛。这澄清了吗?

答案 2 :(得分:0)

@Lennart,Alvin,请考虑以下内容......

DROP TABLE IF EXISTS my_table;

CREATE TABLE my_table (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,val INT NOT NULL);

INSERT INTO my_table (val) VALUES (1),(1),(2),(1),(3),(2),(3),(1),(4);

SELECT * FROM my_table;
+----+-----+
| id | val |
+----+-----+
|  1 |   1 |
|  2 |   1 |
|  3 |   2 |
|  4 |   1 |
|  5 |   3 |
|  6 |   2 |
|  7 |   3 |
|  8 |   1 |
|  9 |   4 |
+----+-----+

让我们删除每个val的最新结果,即...

的结果
SELECT x.* 
  FROM my_table x 
  JOIN 
     ( SELECT val, max(id) max_id FROM my_table GROUP BY val ) y 
    ON y.val = x.val 
   AND y.max_id = x.id;
+----+-----+
| id | val |
+----+-----+
|  8 |   1 |
|  6 |   2 |
|  7 |   3 |
|  9 |   4 |
+----+-----+

因此...

DELETE x 
  FROM my_table x 
  JOIN ( SELECT val, max(id) max_id FROM my_table GROUP BY val ) y 
    ON y.val = x.val 
   AND y.max_id = x.id;

SELECT * FROM my_table;
+----+-----+
| id | val |
+----+-----+
|  1 |   1 |
|  2 |   1 |
|  3 |   2 |
|  4 |   1 |
|  5 |   3 |
+----+-----+