简体   繁体   English

用SQL匹配日期

[英]Matching Dates With SQL

I have two different tables as shown in below and would like to Join them using two columns Product and Date . 我有两个不同的表,如下所示,并且希望使用两列ProductDate来加入它们。 The Table1 has YYYYMMDD Date Format and Table2 has YYYYMM format. Table1具有YYYYMMDD日期格式,而Table2具有YYYYMM格式。 Here in the Table2 it the last business day of the month. 在表Table2它是一个月的最后一个工作日。 Is there any way to Join those two tables. 有什么办法可以连接这两个表。

Table1: 表格1:

Product Date    State
A   20080107    NY
A   20080131    TX
B   20100212    CT
B   20100226    MT
C   20150312    HG
C   20140425    UP

Table2: 表2:

Product Date    Country
A   200801  USA
C   201503  AUS
B   201002  UK
B   201704  FIN
C   200605  IRE
A   200805  CAN

OUTPUT: OUTPUT:

Product Date    State   Country
A   20080131    TX  USA
B   20100226    MT  UK

If I understand correctly, you want all the rows in table1 where table1.date corresponds with the last business day of the month in table2.date . 如果我理解正确的话,你想在所有的行table1地方table1.date在该月的最后一个工作日对应table2.date

I'm going to assume these are real date columns , despite the formatting. 我将假设它们是实际date ,尽管经过了格式化。 If they're not, convert them to real dates. 如果不是,请将其转换为实际日期。 table1.date is already in an acceptable YYYYMMDD format so MySQL will convert it for you. table1.date已经是可接受的YYYYMMDD格式,因此MySQL会为您转换它。 table2.date can be changed to an acceptable YYYYMMDD format with concat(date, "01") . 可以使用concat(date, "01")table2.date更改为可接受的YYYYMMDD格式。 Then you can use MySQL's date functions . 然后,您可以使用MySQL的date函数 I strongly suggest you make this conversion permanent by altering the tables, it will make everything simpler and faster. 我强烈建议您通过更改表使此转换永久化,这将使所有操作变得更加简单和快捷。

MySQL doesn't have a last business day, but it does have last_day and dayofweek (and here is where I sigh about MySQL's inconsistent function name conventions). MySQL没有一个最后一个营业日,但它确实有last_daydayofweek (这里是我感叹一下MySQL的不一致功能名称约定)。 To get the last business day we find the last day of the month, then what day of the week it is, and subtract as appropriate. 要获得最后一个工作日,我们需要找到一个月的最后一天,然后是星期几,并酌情减去。

Annoyingly, dayofweek returns 1 for Sunday, not 0 which makes things a bit more difficult. 烦人的是, dayofweek对于星期日返回1,而不是0,这使事情变得更加困难。

case
    -- Sunday, move to Friday
    when dayofweek(last_day('2010-02-01')) = 1 then last_day('2010-02-01') - 2
    -- Saturday, move to Friday
    when dayofweek(last_day('2010-02-01')) = 7 then last_day('2010-02-01') - 1
    -- Weekday
    when dayofweek(last_day('2010-02-01')) in(2,3,4,5,6) then last_day('2010-02-01') 
    else null
end as last_business_day;

This would be better done as a stored procedure. 最好将它作为存储过程来完成。 Not only does this avoid repetition because we can use variables, it also encapsulate the logic in a neat, testable function. 这样不仅可以避免重复,因为我们可以使用变量,而且还可以将逻辑封装在一个整齐的,可测试的函数中。 We can also declare it deterministic which means MySQL can cache the calculation for the same dates saving some CPU time. 我们也可以声明它是deterministic ,这意味着MySQL可以在相同的日期缓存计算,从而节省一些CPU时间。

create function last_business_day(date date)
returns date
deterministic
begin
    declare last_day date;
    declare last_dow int;

    set last_day = last_day(date);
    set last_dow = dayofweek(last_day);
    return case
        -- Sunday, move to Friday
        when last_dow = 1 then
            last_day - 2
        -- Saturday, move to Friday
        when last_dow = 7 then
            last_day - 1
        -- Weekday
        when last_dow in(2,3,4,5,6) then
            last_day
        else
            null
    end;
end;

Now we can ask last_business_day('2010-02-01') and get 2010-02-26 . 现在我们可以询问last_business_day('2010-02-01')并获取2010-02-26

Armed with this, the query becomes simple. 有了这些,查询变得简单。

select t1.product, t1.date, t1.state, t2.country
from table1 t1
join table2 t2 on t1.product = t2.product and
                  t1.date = last_business_day(t2.date)

Here is your solved SQL: 这是您解决的SQL:

select x.product,x.date,x.state,x.country
from
(select x.product,x.date,x.state,country
from (select product,max(date) date from table1 group by product) t1
join table2 on (left(t1.date,6) = table2.date)
join table1 x on (left(x.date,6) = left(t1.date,6))) x
join (select x.product,max(x.date) date
from (select product,max(date) date from table1 group by product) t1
join table2 on (left(t1.date,6) = table2.date)
join table1 x on (left(x.date,6) = left(t1.date,6))
     group by x.product) y
on (x.product = y.product and x.date = y.date);

Example: 例:

mysql> create table table1(product varchar(20),date varchar(8), state varchar(20));
Query OK, 0 rows affected (0.41 sec)

mysql> insert into table1 values
    -> ('A','20080107','NY'),
    -> ('A','20080131','TX'),
    -> ('B','20100212','CT'),
    -> ('B','20100226','MT'),
    -> ('C','20150312','HG'),
    -> ('C','20140425','UP');
Query OK, 6 rows affected (0.13 sec)
Records: 6  Duplicates: 0  Warnings: 0

mysql> 
mysql> create table table2(Product varchar(20),Date varchar(8),Country varchar(20));
Query OK, 0 rows affected (0.33 sec)

mysql> insert into table2 values
    -> ('A','200801','USA'),
    -> ('C','201503','AUS'),
    -> ('B','201002','UK'),
    -> ('B','201704','FIN'),
    -> ('C','200605','IRE'),
    -> ('A','200805','CAN');
Query OK, 6 rows affected (0.13 sec)
Records: 6  Duplicates: 0  Warnings: 0

mysql> select x.product,x.date,x.state,x.country
    -> from
    -> (select x.product,x.date,x.state,country
    -> from (select product,max(date) date from table1 group by product) t1
    -> join table2 on (left(t1.date,6) = table2.date)
    -> join table1 x on (left(x.date,6) = left(t1.date,6))) x
    -> join (select x.product,max(x.date) date
    -> from (select product,max(date) date from table1 group by product) t1
    -> join table2 on (left(t1.date,6) = table2.date)
    -> join table1 x on (left(x.date,6) = left(t1.date,6))
    ->      group by x.product) y
    -> on (x.product = y.product and x.date = y.date);
+---------+----------+-------+---------+
| product | date     | state | country |
+---------+----------+-------+---------+
| A       | 20080131 | TX    | USA     |
| B       | 20100226 | MT    | UK      |
| C       | 20150312 | HG    | AUS     |
+---------+----------+-------+---------+
3 rows in set (0.01 sec)

Demo 演示

http://www.sqlfiddle.com/#!9/6ef0e5/11 http://www.sqlfiddle.com/#!9/6ef0e5/11

As per OP, date is stored an INT . 根据OP, date存储为INT Find the last date of each month ( FLOOR(date/100) ) for each product on table1 and use that to join with table2. 在表1上找到每个产品的每个月的最后日期( FLOOR(date/100) ),然后将其与表2结合使用。

select 
t1.product,
t1.date,
t1.state,
t2.country
from 
table2 t2
join
(select table1.* 
 from table1 join
 (select product, max(date) lastdayOfMonth 
  from table1
  group by product, floor(date/100)) t 
  on table1.product = t.product and table1.date = t.lastdayofMonth ) t1 
 on 
 t1.product = t2.product
 and
 t1.date = t2.date 

Demo: sqlfiddle 演示: sqlfiddle

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

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