MySQL-存储过程或简单联接,可根据过滤器和最大值将一个表中的值转换为另一个表

时间:2018-10-06 07:29:51

标签: mysql join stored-procedures

我想知道在mysql中执行以下操作的更好方法是什么:

如果我有一个具有以下结构和伪数据的表A:

+------------+-----+
|   Dates    | ID  |
+------------+-----+
| 01/01/2017 | 123 |
| 02/01/2017 | 123 |
| 03/01/2017 | 123 |
| 04/01/2017 | 123 |
| 06/01/2017 | 123 |
| 07/01/2017 | 123 |
| 01/01/2017 | 124 |
| 02/01/2017 | 124 |
| 03/01/2017 | 124 |
| 04/01/2017 | 124 |
| 06/01/2017 | 124 |
| 07/01/2017 | 124 |
+------------+-----+

和带有一些信息的表B是我想要从中获取属性数据:

+------------+-----+-----------+
|   Dates    | ID  | Attribute |
+------------+-----+-----------+
| 29/12/2016 | 123 | AA        |
| 30/12/2016 | 123 | AB        |
| 31/12/2016 | 123 | AC        |
| 01/01/2017 | 123 | AD        |
| 03/01/2017 | 123 | AF        |
| 04/01/2017 | 123 | AA        |
| 07/01/2017 | 123 | AF        |
| 10/01/2017 | 123 | AC        |
| 27/12/2016 | 124 | BA        |
| 28/12/2016 | 124 | BB        |
| 29/12/2016 | 124 | BC        |
| 30/12/2016 | 124 | BD        |
| 31/12/2016 | 124 | BE        |
| 02/01/2017 | 124 | BF        |
| 04/01/2017 | 124 | BA        |
| 06/01/2017 | 124 | AA        |
| 07/01/2017 | 124 | AC        |
| 11/01/2017 | 124 | BF        |
+------------+-----+-----------+

根据以下条件,一个人将如何联接这两个表以获得属性信息:

  1. 在表A中的许多记录中,表B中没有匹配的日期,因此不能直接和简单地连接ID和日期;

  2. 如果在表B中没有匹配的日期d,则对于表A中的给定ID,那么我需要从紧接的前一个日期获取属性(该前一个日期可以是前一天或日期d)前几天。

我想要获得的结果表如下所示:

+----------------------+---------------------+----------------------------+
| Dates (from table A) | ID ( from table A ) | Attribute ( from table B ) |
+----------------------+---------------------+----------------------------+
| 01/01/2017           |                 123 | AD                         |
| 02/01/2017           |                 123 | AD                         |
| 03/01/2017           |                 123 | AF                         |
| 04/01/2017           |                 123 | AA                         |
| 06/01/2017           |                 123 | AA                         |
| 07/01/2017           |                 123 | AF                         |
| 01/01/2017           |                 124 | BE                         |
| 02/01/2017           |                 124 | BF                         |
| 03/01/2017           |                 124 | BF                         |
| 04/01/2017           |                 124 | BA                         |
| 06/01/2017           |                 124 | AA                         |
| 07/01/2017           |                 124 | AC                         |
+----------------------+---------------------+----------------------------+

请注意,例如: 对于2017年2月1日的ID = 123,表B中没有任何记录,因此我需要从前一天获得属性,在这种情况下,这是从2017年1月1日开始的属性-属性= AD。

如您所见,这是类似于我的真实数据的伪数据,并且我的真实数据在每个表中都有数百个注册表。因此,我也在寻找一种可以很好地运行数据库的解决方案。我认为也许我们需要一个存储过程,该存储过程遍历表A的每一行并获得我期望的结果,这是一个好主意吗?同时,我想知道是否可以通过join操作来完成...我现在真的很困惑:)

我希望这个解释很清楚,如果以前已经回答过类似的问题,我深感抱歉。但是,我已经研究了这几天,并且进行了大量搜索,但是没有找到类似问题的答案。 预先感谢您的帮助。 干杯。

编辑:我更改了一个或多个therms注册表的记录。

1 个答案:

答案 0 :(得分:1)

一种方法是使用相关子查询,例如

drop table if exists tb;
drop table if exists ta;
create table ta(Dates date,    ID  int);
insert into ta values
(str_to_date('01/01/2017','%d/%m/%Y'),123), 
(str_to_date('02/01/2017','%d/%m/%Y'),123), 
(str_to_date('03/01/2017','%d/%m/%Y'),123), 
(str_to_date('04/01/2017','%d/%m/%Y'),123), 
(str_to_date('06/01/2017','%d/%m/%Y'),123), 
(str_to_date('07/01/2017','%d/%m/%Y'),123), 
(str_to_date('01/01/2017','%d/%m/%Y'),124), 
(str_to_date('02/01/2017','%d/%m/%Y'),124), 
(str_to_date('03/01/2017','%d/%m/%Y'),124), 
(str_to_date('04/01/2017','%d/%m/%Y'),124), 
(str_to_date('06/01/2017','%d/%m/%Y'),124), 
(str_to_date('07/01/2017','%d/%m/%Y'),124);

create table tb(   Dates  date,   ID int ,Attribute varchar(2));
insert into tb values
( str_to_date('29/12/2016','%d/%m/%Y'),123 , 'AA'),        
( str_to_date('30/12/2016','%d/%m/%Y'),123 , 'AB'),        
( str_to_date('31/12/2016','%d/%m/%Y'),123 , 'AC'),        
( str_to_date('01/01/2017','%d/%m/%Y'),123 , 'AD'),        
( str_to_date('03/01/2017','%d/%m/%Y'),123 , 'AF'),        
( str_to_date('04/01/2017','%d/%m/%Y'),123 , 'AA'),        
( str_to_date('07/01/2017','%d/%m/%Y'),123 , 'AF'),        
( str_to_date('10/01/2017','%d/%m/%Y'),123 , 'AC'),        
( str_to_date('27/12/2016','%d/%m/%Y'),124 , 'BA'),        
( str_to_date('28/12/2016','%d/%m/%Y'),124 , 'BB'),        
( str_to_date('29/12/2016','%d/%m/%Y'),124 , 'BC'),        
( str_to_date('30/12/2016','%d/%m/%Y'),124 , 'BD'),        
( str_to_date('31/12/2016','%d/%m/%Y'),124 , 'BE'),        
( str_to_date('02/01/2017','%d/%m/%Y'),124 , 'BF'),        
( str_to_date('04/01/2017','%d/%m/%Y'),124 , 'BA'),        
( str_to_date('06/01/2017','%d/%m/%Y'),124 , 'AA'),        
( str_to_date('07/01/2017','%d/%m/%Y'),124 , 'AC'),        
( str_to_date('11/01/2017','%d/%m/%Y'),124 , 'BF');


select ta.dates, ta.id,(select attribute from tb where tb.id = ta.id and tb.dates <= ta.dates order by tb.dates desc limit 1) attribute
from ta;

+------------+------+-----------+
| dates      | id   | attribute |
+------------+------+-----------+
| 2017-01-01 |  123 | AD        |
| 2017-01-02 |  123 | AD        |
| 2017-01-03 |  123 | AF        |
| 2017-01-04 |  123 | AA        |
| 2017-01-06 |  123 | AA        |
| 2017-01-07 |  123 | AF        |
| 2017-01-01 |  124 | BE        |
| 2017-01-02 |  124 | BF        |
| 2017-01-03 |  124 | BF        |
| 2017-01-04 |  124 | BA        |
| 2017-01-06 |  124 | AA        |
| 2017-01-07 |  124 | AC        |
+------------+------+-----------+
12 rows in set (0.01 sec)