【问题标题】:Combining multiple similar queries into 1将多个相似查询合并为 1
【发布时间】:2017-05-04 07:51:57
【问题描述】:

我在一些python代码中有以下查询,

    sel = select([staff.c.name,
                      staff.c.start_date,
                      staff.c.leave_allowance,
                      ]) \
            .select_from(staff) \
            .where(staff.c.name == request.args.get('user')) \
            .group_by(staff.c.name, staff.c.leave_allowance, staff.c.start_date)

        staff_member = ZS.db_connect().execute(sel).fetchone()
        staff_member = dict(staff_member)

sel1 = select([staff.c.start_date,
                func.sum(leave.c.hours).label('hours_taken')
                ]) \
        .select_from(join(staff, leave, (staff.c.name == leave.c.name))) \
        .where(leave.c.leave_start >= '2016-01-01') \
        .where(leave.c.leave_end <= '2016-03-30') \
        .where(leave.c.hr_status == 'RP_Approved') \
        .where(leave.c.name == request.args.get('user')) \
        .group_by(staff.c.name, staff.c.start_date)

        jan_user = ZS.db_connect().execute(sel1).fetchone()
        if(jan_user):
            jan_user = dict(jan_user)
            staff_member['JanMarTaken'] = jan_user['hours_taken']
        else:

            staff_member['JanMarTaken'] = 0

        sel2 = select([staff.c.start_date,
                func.sum(leave.c.hours).label('hours_taken')
                ]) \
            .select_from(join(staff, leave, (staff.c.name == leave.c.name))) \
            .where(leave.c.leave_start >= '2016-04-01') \
            .where(leave.c.leave_end <= '2016-09-30') \
            .where(leave.c.hr_status == 'RP_Approved') \
            .where(leave.c.name == request.args.get('user')) \
            .group_by(staff.c.name, staff.c.start_date)

        mar_user = ZS.db_connect().execute(sel2).fetchone()
        if(mar_user):
            mar_user = dict(mar_user)
            staff_member['MarSeptHours'] = mar_user['hours_taken']
        else:
            staff_member['MarSeptHours'] = 0


        sel2 = select([staff.c.start_date,
                func.sum(leave.c.hours).label('hours_taken')
                ]) \
            .select_from(join(staff, leave, (staff.c.name == leave.c.name))) \
            .where(leave.c.leave_start >= '2016-10-01') \
            .where(leave.c.leave_end <= '2016-12-31') \
            .where(leave.c.hr_status == 'RP_Approved') \
            .where(leave.c.name == request.args.get('user')) \
            .group_by(staff.c.name, staff.c.start_date)

        oct_user = ZS.db_connect().execute(sel2).fetchone()
        if(oct_user):
            mar_user = dict(mar_user)
            staff_member['OctDecHours'] = mar_user['hours_taken']
        else:
            staff_member['OctDecHours'] = 0

查询基本上都做同样的事情,即按名称搜索用户并检索某些日期之间记录的一些数据,我需要一年中 3 个部分的数据,所以目前我查询数据库 3 次使用不同的日期参数,有没有办法通过 1 个查询来做到这一点,以获得更好的性能?

【问题讨论】:

    标签: python sql-server sqlalchemy


    【解决方案1】:

    在 SQL 中执行此操作,以便您可以转换为存储过程,我添加了一个变量 @YearToCheck 来传递报告年份。

    让我们做一些测试数据:

    DECLARE @Staff TABLE
    (
        Name VARCHAR(100),
        Emp_Start_Date DATETIME,
        Emp_End_Date DATETIME,
        Emp_Leave_Allowance INT
    )
    
    DECLARE @Leave TABLE
    (
        Name VARCHAR(100),
        Leave_Start DATETIME,
        Leave_End DATETIME,
        Hr_Status VARCHAR(100)
    )
    
    DECLARE @YearToCheck INT = 2016
    
    INSERT INTO @Staff 
    ( Name, Emp_Start_Date, Emp_End_Date, Emp_Leave_Allowance )
    VALUES
    ( 'Fred', DATEFROMPARTS( 2016, 1, 3 ), NULL, 10 ),
    ( 'Wilma', DATEFROMPARTS( 2014, 2, 1 ), NULL, 10 ),
    ( 'Barney', DATEFROMPARTS( 2015, 7, 1 ), NULL, 10 ),
    ( 'Betty', DATEFROMPARTS( 2014, 2, 1 ), NULL, 10 );
    
    INSERT INTO @Leave
    ( Name, Leave_Start, Leave_End, Hr_Status )
    VALUES
    ( 'Fred', DATEFROMPARTS( 2015, 12, 1), DATEFROMPARTS( 2016, 6, 1), 'RP_Approved'),
    ( 'Fred', DATEFROMPARTS( 2016, 7, 1), DATEFROMPARTS( 2016, 8, 1), 'RP_Approved'),
    ( 'Wilma', DATEFROMPARTS( 2016, 1, 10), DATEFROMPARTS( 2016, 1, 15), 'RP_Approved'),
    ( 'Barney', DATEFROMPARTS( 2016, 6, 10), DATEFROMPARTS( 2016, 7, 10), 'RP_Approved'),
    ( 'Betty', DATEFROMPARTS( 2016, 7, 30), DATEFROMPARTS( 2016, 8, 5), 'RP_Approved'),
    ( 'Betty', DATEFROMPARTS( 2016, 9, 29), DATEFROMPARTS( 2016, 10, 3), 'RP_Approved'),
    ( 'Betty', DATEFROMPARTS( 2015, 1, 1), DATEFROMPARTS( 2017, 1, 5), 'RP_Approved');
    

    现在让我们运行一个查询来查找不同的日期分区

    第 1 节:1-1 到

    第 2 节:4-1 至

    第 3 节:10-1 至

    SELECT s.Name,      
            CASE WHEN (l.Leave_Start <= DATEFROMPARTS( @YearToCheck, 4, 1)) AND (DATEFROMPARTS( @YearToCheck, 1, 1) <= l.Leave_End)  
                THEN
                    DATEDIFF( DAY, 
                        CASE WHEN l.Leave_Start < DATEFROMPARTS( @YearToCheck, 1, 1) THEN DATEFROMPARTS( @YearToCheck, 1, 1) ELSE l.Leave_Start END,
                        CASE WHEN l.Leave_End > DATEFROMPARTS( @YearToCheck, 4, 1) THEN DATEFROMPARTS( @YearToCheck, 4, 1) ELSE DATEADD(DAY, 1, l.Leave_End) END ) --Inclusive
                ELSE 0
            END AS FirstSection,
            CASE WHEN (l.Leave_Start <= DATEFROMPARTS( @YearToCheck, 10, 1)) AND (DATEFROMPARTS( @YearToCheck, 4, 1) <= l.Leave_End)  
                THEN
                    DATEDIFF( DAY, 
                        CASE WHEN l.Leave_Start < DATEFROMPARTS( @YearToCheck, 4, 1) THEN DATEFROMPARTS( @YearToCheck, 4, 1) ELSE l.Leave_Start END,
                        CASE WHEN l.Leave_End > DATEFROMPARTS( @YearToCheck, 10, 1) THEN DATEFROMPARTS( @YearToCheck, 10, 1) ELSE DATEADD(DAY, 1, l.Leave_End) END ) --Inclusive
                ELSE 0
            END AS SecondSection,
            CASE WHEN (l.Leave_Start <= DATEFROMPARTS( @YearToCheck + 1, 1, 1)) AND (DATEFROMPARTS( @YearToCheck, 10, 1) <= l.Leave_End)  
                THEN
                    DATEDIFF( DAY, 
                        CASE WHEN l.Leave_Start < DATEFROMPARTS( @YearToCheck, 10, 1) THEN DATEFROMPARTS( @YearToCheck, 10, 1) ELSE l.Leave_Start END,
                        CASE WHEN l.Leave_End > DATEFROMPARTS( @YearToCheck + 1, 1, 1) THEN DATEFROMPARTS( @YearToCheck + 1, 1, 1) ELSE DATEADD(DAY, 1, l.Leave_End) END ) --Inclusive
                ELSE 0
            END AS ThirdSection
        FROM @Staff s
        INNER JOIN @Leave l
            ON l.Name = s.Name
        WHERE l.Hr_Status = 'RP_Approved'
    

    这是按天计算的输出数据:

    Name    FirstSection    SecondSection   ThirdSection
    Fred    91  62  0
    Fred    0   32  0
    Wilma   6   0   0
    Barney  0   31  0
    Betty   0   7   0
    Betty   0   2   3
    Betty   91  183 92
    

    现在,我不检查假期范围是否重叠,或者日子是否与周末重叠,等等......因为这不是问题,可以添加,但希望这是你可以用来从 python 中提取逻辑,让 sql server 处理工作。

    【讨论】:

      猜你喜欢
      • 2021-12-13
      • 1970-01-01
      • 1970-01-01
      • 2020-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多