利用 SQLalchemy 为各种可能的列值组合生成分位数

34 阅读3分钟

我们需要一个 SQL 服务器查询,在查询中为数量不断增长的变量生成 n 分位数,这些变量按各种排列组合进行组合。示例中包含了这部分的内容:

statement 1:
ntile(10) over (partition by  MAUorALL, User_Type, fsi.Month_ID 
                    order by Objects_Created) AS Ntile_Mon_Objects_Created,

statement 2:
ntile(10) over (partition by  MAUorALL, User_Type, fsi.Month_ID, *Country*
          order by Objects_Created) AS Ntile_Country_Objects_Created

statement 3:
ntile(10) over (partition by  MAUorALL, User_Type, fsi.Month_ID, *User*_Type
                 order by Objects_Created) AS Ntile_UT_Objects_Created

您可以看到这些语句是相同的,只是在第二个和第三个语句中创建了 countryuser type 这两个用 * 标注的列。因此,我们为 Objects_Created 这个变量在不同层次上获取分位数,并且我们还必须为这些变量的各种可能的排列组合获取分位数,例如:

statement 4:
ntile(10) over (partition by  MAUorALL, User_Type, fsi.Month_ID, *Country, User_Type*
            order by Objects_Created) AS Ntile_Country_UT_Objects_Created

我们可以手动对这些排列组合进行编码,但是在一定程度上,如果可以使用 sqlalchemy 来执行这些变量的所有排列组合,那可能会使事情变得更容易。

2、解决方案

一个可行的解决方案是使用 SQLalchemy 中的 generate() 函数来生成所有可能的列值组合。generate() 函数允许我们在查询中使用一个子查询,该子查询生成一组值。我们可以使用这个函数来生成所有可能的列值组合,然后使用这些组合作为我们 PARTITION BY 子句中的分区键。

例如,我们可以使用以下代码生成所有可能的 MAUorALLUser_Type 的组合:

from sqlalchemy import func, select

combinations = (
    select([MAUorALL, User_Type])
    .distinct()
    .subquery()
)

然后,我们可以使用 generate() 函数将这些组合作为我们 PARTITION BY 子句中的分区键。例如,我们可以使用以下代码来计算 Objects_Created 的分位数,并按 MAUorALLUser_Type 分区:

ntile_mon_objects_created = func.ntile(10).over(
    partition_by=combinations.c.MAUorALL, combinations.c.User_Type,
    order_by=Objects_Created
)

我们还可以使用 generate() 函数来生成所有可能的 MAUorALLUser_TypeCountry 的组合。例如,我们可以使用以下代码来计算 Objects_Created 的分位数,并按 MAUorALLUser_TypeCountry 分区:

ntile_country_objects_created = func.ntile(10).over(
    partition_by=combinations.c.MAUorALL, combinations.c.User_Type, combinations.c.Country,
    order_by=Objects_Created
)

这种解决方案使我们能够为大量变量生成分位数,而无需手动编码所有可能的排列组合。这可以为我们节省大量时间和精力,尤其是在处理大量变量时。

代码例子

以下是一个完整的代码例子,演示如何使用 SQLalchemy 来为各种可能的列值组合生成分位数:

from sqlalchemy import create_engine, Column, Integer, String, func
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('postgresql://user:password@host:port/database')
Session = sessionmaker(bind=engine)
session = Session()

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    MAUorALL = Column(String)
    User_Type = Column(String)
    Country = Column(String)
    Objects_Created = Column(Integer)

combinations = (
    select([User.MAUorALL, User.User_Type])
    .distinct()
    .subquery()
)

ntile_mon_objects_created = func.ntile(10).over(
    partition_by=combinations.c.MAUorALL, combinations.c.User_Type,
    order_by=User.Objects_Created
)

results = session.query(User, ntile_mon_objects_created).all()

for user, ntile in results:
    print(user.MAUorALL, user.User_Type, user.Objects_Created, ntile)

这个例子首先创建一个 SQLalchemy 引擎并创建一个会话。然后,它定义了一个名为 User 的模型类,其中包含我们想要查询的列。接着,它使用 generate() 函数生成所有可能的 MAUorALLUser_Type 的组合。然后,它使用 ntile() 函数计算 Objects_Created 的分位数,并按 MAUorALLUser_Type 分区。最后,它运行查询并打印结果。