python - 在左连接中使用类似 SQL 的连接和过滤器(之间)合并表

标签 python pandas tsql join filter

所以我有这两个表,我想在其中执行 left join 并过滤 df1 中的 date 列介于两者之间的行df2 中的 fromto 列。

注意 第 6 行,它没有最终会导致问题的 ClockInDate

df1:

  Company Resource ClockInDate
0       A     ResA  2019-02-09
1       A     ResB  2019-02-09
2       A     ResC  2019-02-09
3       B     ResD  2019-02-09
4       B     ResE  2019-02-09
5       B     ResF  2019-02-09
6       B     ResG         NaT

df2:

  Company Resource EffectiveFrom EffectiveTo
0       A     ResA    2018-01-01  2018-12-31
1       A     ResA    2019-01-01  2099-12-31
2       A     ResB    2018-01-01  2018-12-31
3       A     ResB    2019-01-01  2099-12-31
4       B     ResE    2018-01-01  2018-12-31
5       B     ResE    2019-01-01  2099-12-31
6       B     ResF    2018-01-01  2018-12-31
7       B     ResF    2019-01-01  2099-12-31
8       B     ResG    2018-01-01  2018-12-31
9       B     ResG    2019-01-01  2099-12-31

我想我可以在 pandas 中使用 left merge 来做到这一点,然后应用过滤器。
但它给出了不同的输出。

因此,在 SQL 中,您可以像这样在 ON 子句中包含此过滤器,但这与在 WHERE 子句中加入后包含此过滤器不同:

       SELECT t1.company,
              t1.resource,
              t2.company,
              t2.resource,
              t1.ClockInDate,
              t2.EffectiveFrom,
              t2.EffectiveTo
       FROM table1 t1
       LEFT JOIN table2 t2 ON t1.resource = t2.resource
                            AND t1.company = t2.company
                            AND t1.ClockInDate BETWEEN t2.EffectiveFrom AND t2.EffectiveTo

注意部分:AND t1.ClockInDate BETWEEN t2.EffectiveFrom AND t2.EffectiveTo
注意:SQL代码中df1t1df2t2

SQL 输出(这是我的预期输出):

    t1.Company  t1.Resource t1.ClockInDate  t2.EffectiveFrom    t2.EffectiveTo
0   A           ResA        2019-02-09      2019-01-01          2099-12-31
1   A           ResB        2019-02-09      2019-01-01          2099-12-31
2   A           ResC        NaT             NaT                 NaT
3   B           ResD        NaT             NaT                 NaT
4   B           ResE        2019-02-09      2019-01-01          2099-12-31
5   B           ResF        2019-02-09      2019-01-01          2099-12-31
6   B           ResG        NaT             NaT                 NaT

所以这是我在 Python 中的代码:

Python 输出

df_merge = pd.merge(df1, df2, on=['Company', 'Resource'], how='left')
df_final = df_merge[df_merge.ClockInDate.between(df_merge.EffectiveFrom, df_merge.EffectiveTo) | df_merge.EffectiveFrom.isnull()]

#Output:

    Company Resource    ClockInDate EffectiveFrom   EffectiveTo
1   A       ResA        2019-02-09  2019-01-01      2099-12-31
3   A       ResB        2019-02-09  2019-01-01      2099-12-31
4   A       ResC        2019-02-09  NaT             NaT
5   B       ResD        2019-02-09  NaT             NaT
7   B       ResE        2019-02-09  2019-01-01      2099-12-31
9   B       ResF        2019-02-09  2019-01-01      2099-12-31

请注意,我的 Python 输出中没有包含资源 ResG 的最后一行。

复制并粘贴代码以重现DataFrames

df1 = pd.DataFrame({'Company':['A', 'A', 'A', 'B', 'B', 'B', 'B'],
                    'Resource':['ResA', 'ResB','ResC', 'ResD', 'ResE', 'ResF', 'ResG'],
                    'ClockInDate':['2019-02-09', '2019-02-09', '2019-02-09', '2019-02-09', '2019-02-09', '2019-02-09', '']})

df1['ClockInDate'] = pd.to_datetime(df1.ClockInDate)

df2 = pd.DataFrame({'Company':['A','A', 'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B'],
                    'Resource':['ResA', 'ResA', 'ResB', 'ResB', 'ResE', 'ResE', 'ResF', 'ResF', 'ResG', 'ResG'],
                    'EffectiveFrom':['2018-01-01', '2019-01-01', '2018-01-01', '2019-01-01', '2018-01-01', '2019-01-01', '2018-01-01', '2019-01-01', '2018-01-01', '2019-01-01'],
                    'EffectiveTo':['2018-12-31', '2099-12-31', '2018-12-31', '2099-12-31', '2018-12-31', '2099-12-31', '2018-12-31', '2099-12-31', '2018-12-31', '2099-12-31']})

df2['EffectiveFrom'] = pd.to_datetime(df2.EffectiveFrom)
df2['EffectiveTo'] = pd.to_datetime(df2.EffectiveTo)

最佳答案

因此,在完成这个项目后,我获得了更多见解。我找到了一个解决方案,但希望有一个更干净 的解决方案。但这可行:我们可以连接原始数据帧中具有 ClockIndate.isnull 的行:

df_merge = pd.merge(df1, df2, on=['Company', 'Resource'], how='left')

df_filter = df_merge[df_merge.ClockInDate.between(df_merge.EffectiveFrom, df_merge.EffectiveTo) | df_merge.EffectiveFrom.isnull()]

df_final = pd.concat([df_filter, df1[df1.ClockInDate.isnull()]], sort=True)

print(df_final)
  ClockInDate Company EffectiveFrom EffectiveTo Resource
1  2019-02-09       A    2019-01-01  2099-12-31     ResA
3  2019-02-09       A    2019-01-01  2099-12-31     ResB
4  2019-02-09       A           NaT         NaT     ResC
5  2019-02-09       B           NaT         NaT     ResD
7  2019-02-09       B    2019-01-01  2099-12-31     ResE
9  2019-02-09       B    2019-01-01  2099-12-31     ResF
6         NaT       B           NaT         NaT     ResG

关于python - 在左连接中使用类似 SQL 的连接和过滤器(之间)合并表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54591008/

相关文章:

python - 写入后中止缓慢刷新到磁盘?

python - 使用 pandas 将列值转换为行

python - 使用 pandas 重置 CSV 的列位置

sql-server - 从 C# .NET 中的 TSQL FOR XML 语句读取大型 XML 字符串

SQL 'Round' 将日期更新为一周中的给定日期

python - 带续行的赋值 - Python

javascript - 在没有启用javascript的网页上使用 Mechanize 和美汤

python - 奇怪的未知 lambda 语法

Python & Pandas - pd.Series int32 和 int64 之间的区别

sql-server - 从 xp_cmdshell 调用时 psexec 无法正常工作