Sql 避免多个子查询

Sql 避免多个子查询,sql,postgresql,Sql,Postgresql,我正在处理一个长的、查询量很大的表>5亿个条目,因此避免大型查询非常重要 目前,我需要得到一些值,条件会在一瞬间解释得更好,然后,检查这些值是否在另一组值中,所有这些值都指向同一个字段。我正在使用with创建表的视图 下面是表语法:tableemployee +--------+-------------+-----------+--------+---------+-----------+ | period | employee_id | operation | sub_op | paymen

我正在处理一个长的、查询量很大的表>5亿个条目,因此避免大型查询非常重要

目前,我需要得到一些值,条件会在一瞬间解释得更好,然后,检查这些值是否在另一组值中,所有这些值都指向同一个字段。我正在使用with创建表的视图

下面是表语法:tableemployee

+--------+-------------+-----------+--------+---------+-----------+
| period | employee_id | operation | sub_op | payment | work_zone |
+--------+-------------+-----------+--------+---------+-----------+
期间的格式为“YYMM”,一个期间指一个月

当然,这个表比这个示例要长得多,但我只需要查询中的那些字段。我需要的是一个简短的解释,然后是查询本身

我需要获得当前期间的所有员工id,并支付至少250美元的可观款项和一个特定的操作,首先我将该操作分组为具有子操作值的操作。询问的操作值为97,在查询中,您将看到我如何对其进行分组

现在,对于这些值,我按工作区和分组的操作值对它们进行分组。现在子查询开始了。。。我需要:

所有这些值都不是过去时期的值。 所有这些值都不是过去36个时期3年内的值。 过去36个周期中至少有一个周期中的所有值。 过去36个周期中至少有一个周期中的所有值,但操作不同。 所有这些价值至少在过去36个时期中的一个时期,但付款低于250美元。 这是我到目前为止提出的问题。我用的是'1109'句点

CREATE OR REPLACE VIEW hired_fired AS
WITH query_hired_fired AS ( 
    SELECT work_zone, operation, sub_op, employee_id,
        CASE 
            WHEN operation = 97 THEN 
                CASE 
                    WHEN sub_op IN (1,3,5) THEN 'Cookers' 
                    WHEN sub_op IN (2,6) THEN 'Waitress' 
                    WHEN sub_op IN (4,7,8,9,10) THEN 'Cashier'
                    WHEN sub_op = 11 THEN 'Security' 
                    WHEN sub_op IN (12,13) THEN 'Cleaners' 
                    ELSE 'Others' 
                END
        END AS opgroup
    FROM employee 
    WHERE period = 1109 AND payment >= 250 AND operation = 97
)
SELECT 201109 AS periodo, opgroup, work_zone
(SELECT COUNT(DISTINCT employee_id) FROM query_hired_fired WHERE employee_id NOT IN (SELECT employee_id FROM employee WHERE period = 1108 AND payment >= 250 AND operation = 97)) AS total, 
(SELECT COUNT(DISTINCT employee_id) FROM query_hired_fired WHERE employee_id NOT IN (SELECT employee_id FROM employee WHERE period BETWEEN 0808 AND 1108 AND payment >= 250 AND operation = 97)) AS absolut,
(SELECT COUNT(DISTINCT employee_id) FROM query_hired_fired WHERE employee_id IN (SELECT employee_id FROM employee WHERE period BETWEEN 0808 AND 1108 AND payment >= 250 AND operation = 97)) AS reincorporated,
(SELECT COUNT(DISTINCT employee_id) FROM query_hired_fired WHERE employee_id IN (SELECT employee_id FROM employee WHERE period BETWEEN 0808 AND 1108 AND payment >= 250 AND operation != 97)) AS operation_change,
(SELECT COUNT(DISTINCT employee_id) FROM query_hired_fired WHERE employee_id IN (SELECT employee_id FROM employee WHERE period BETWEEN 0808 AND 1108 AND payment < 250 AND operation = 97)) AS raised,
FROM query_hired_fired
GROUP BY work_zone, opgroup
所以,我的问题是。。。我是否可以在没有所有子查询的情况下执行此查询?我认为这将需要几个小时来运行,而这是不可能的工作与这个表

对不起,如果我有什么不清楚的地方,我会尽快回答所有的疑问。谢谢。

尝试以下查询:

WITH query_hired_fired AS ( 
    SELECT work_zone, operation, sub_op, employee_id,
        CASE 
            WHEN operation = 97 THEN 
                CASE 
                    WHEN sub_op IN (1,3,5) THEN 'Cookers' 
                    WHEN sub_op IN (2,6) THEN 'Waitress' 
                    WHEN sub_op IN (4,7,8,9,10) THEN 'Cashier'
                    WHEN sub_op = 11 THEN 'Security' 
                    WHEN sub_op IN (12,13) THEN 'Cleaners' 
                    ELSE 'Others' 
                END
        END AS opgroup
    FROM employee 
)
SELECT opgroup, work_zone,
       SUM( x_period_1109 * x_total )            As total,
       SUM( x_period_1109 * x_absolut )          As absolut,
       SUM( x_period_1109 * x_reincorporated )   As reincorporated,
       SUM( x_period_1109 * x_operation_change ) As operation_change,
       SUM( x_period_1109 * x_raised )           As raised
FROM (
    SELECT opgroup, work_zone, employee_id,
           MAX( CASE WHEN period = 1108 AND payment >= 250 AND operation = 97 THEN 1 ELSE 0 END) as x_total,
           MAX( CASE WHEN period = 1108 AND payment >= 250 AND operation = 97 THEN 1 ELSE 0 END ) as x_absolut,
           MAX( CASE WHEN period BETWEEN 0808 AND 1108 AND payment >= 250 AND operation = 97 THEN 1 ELSE 0 END ) as x_reincorporated,
           MAX( CASE WHEN period BETWEEN 0808 AND 1108 AND payment >= 250 AND operation != 97 THEN 1 ELSE 0 END ) as x_operation_change,
           MAX( CASE WHEN period BETWEEN 0808 AND 1108 AND payment < 250 AND operation = 97 THEN 1 ELSE 0 END ) as x_raised,
           MAX( CASE WHEN period = '1109' AND payment >= 250 AND operation = 97 THEN 1 ELSE 0 END ) As x_period_1109
    FROM query_hired_fired
    WHERE period BETWEEN 0808 AND 1109
    GROUP BY opgroup, work_zone, employee_id
) x
GROUP BY work_zone, opgroup
查询中的条件是:1108和0808之间的值始终为false,
我想应该是这样的:在0808和1108之间,我有点像科迪尔科,但被一个包裹着。内部PreCalc查询的前提是,如果每个员工满足条件,则为他们计算一行,标记为1或0。由于您的所有条件都基于范围,即仅为1108或介于0808和1108之间,因此该子查询只获取0808和1108之间的所有记录,因此它将简化复杂case/when条件的可读性。我应用它的唯一条件是你第一次特别寻找准确的前一个时期。也就是说,其余的项目是支付金额的限定符,是否为97。因此,对于任何员工,标志将分别设置为1或0

现在,这将应用于执行SUM/CASE的外部查询。为了解释您的不在,我正在寻找给定的标志=0,因此不符合基础数据的要求,而标志=1则符合基础数据的要求

由于预查询也计算了opgroup,所以它被很好地包装起来

我会确保您的表在 期间、员工id、工作区以帮助优化。您可以进一步使用索引键使其成为覆盖索引,但首先要了解它是如何工作的

SELECT
      201109 AS periodo, 
      work_zone, 
      opgroup,
      SUM( case when PreCalc.LPOver250 == 0 end ) as EmpsNotInLastPeriodOver250,
      SUM( case when PreCalc.Over250Op97 == 0 end ) as EmpsNotInOver250Per97,
      SUM( case when PreCalc.Over250Op97 == 1 end ) as EmpsInOver250Per97,
      SUM( case when PreCalc.Over250NotOp97 == 1 end ) as EmpsOver250NotInOp97,
      SUM( case when PreCalc.Under250 == 1 end ) as EmpsUnder250
   from
      ( SELECT
              Employee_ID,
              work_zone, 
              CASE WHEN operation = 97 THEN 
                   CASE WHEN sub_op IN (1,3,5) THEN 'Cookers' 
                        WHEN sub_op IN (2,6) THEN 'Waitress' 
                        WHEN sub_op IN (4,7,8,9,10) THEN 'Cashier'
                        WHEN sub_op = 11 THEN 'Security' 
                        WHEN sub_op IN (12,13) THEN 'Cleaners' 
                        ELSE 'Others' 
                   END
              END AS opgroup, 
              MAX( case when period = 1108 
                        and payment >= 250 
                        and operation = 97 then 1 else 0 end ) as LPOver250,
              MAX( case when payment >= 250 
                        and operation = 97 then 1 else 0 end ) as Over250Op97,
              MAX( case when payment >= 250 
                        and operation != 97 then 1 else 0 end ) as Over250NotOp97,
              MAX( case when payment < 250 
                        and operation = 97 then 1 else 0 end ) as Under250
           from
              employee 
           where
              period between 0808 and 1108
           group by
              Employee_ID,
              work_zone, 
              opgroup ) PreCalc
   group by
      work_zone, 
      opgroup

感谢您的更正,已经在问题中编辑。也谢谢你的回答