[英]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
. 我有两个不同的表,如下所示,并且希望使用两列
Product
和Date
来加入它们。 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_day
和dayofweek
(这里是我感叹一下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);
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)
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.