【问题标题】:Pivot two columns and keep the values same in sql旋转两列并在 sql 中保持相同的值
【发布时间】:2022-01-12 21:34:07
【问题描述】:

我创建了一个查询来获取不同的时间类型和小时

SELECT calc_time.hours             measure,
       calc_time.payroll_time_type elements,
       calc_time.person_id,
       calc_time.start_time
FROM   hwm_tm_rep_work_hours_sum_v calc_time,
       per_all_people_f papf
WHERE  grp_type_id = 200
AND    payroll_time_type IN ( 'Afternoon shift',
                             'TL',
                             'Evening shift',
                             'Regular Pay ',
                             'OT' )
AND    (To_date(To_char(calc_time.start_time, 'YYYY-MM-DD') , 'YYYY-MM-DD') BETWEEN To_date(To_char(:From_Date, 'YYYY-MM-DD'), 'YYYY-MM-DD')
        AND To_date( To_char(:To_Date, 'YYYY-MM-DD'), 'YYYY-MM-DD' ))
AND    papf.person_id = calc_time.person_id

我得到像 -

这样的输出
Start_time     person_id                 elements            measure
01-Jan-2021     198                     Regular Pay           10
01-Jan-2021     198                       OT                  2
01-jAN-2021     198                     Afternoon shift       2
16-JAN-2021     198                     Regular Pay           10
17-JAN-2021     198                     OT                    3
20-JAN-2021     198                     EVENING SHIFT         8


08-JAN-2021     11                      Regular Pay           8
09-JAN-2021     11                        OT                  1
08-JAN-2021     11                          tl                2
10-JAN-2021     12                      Evening shift         9
11-JAN-2021     12                     Evening shift         9

我希望此输出在我作为参数传递的两个日期内显示如下 - 就像 2021 年 1 月 1 日和 2021 年 1 月 31 日的参数一样

 person_id        Regular_pay       OT          OTHER_MEASURE               OTHER_CODE
   198                   20           5             2                       Afternoon shift
   198                   20           5             8                     EVENING SHIFT
   11                     8           1             2                           TL
   12                                               18                        Evening shift
   

因此,常规工资和 OT 在单独列中的总和以及 other_measure 和 other_code 中的所有其他列

如何调整主查询来实现这一点?

【问题讨论】:

标签: sql oracle


【解决方案1】:

你可以使用:

SELECT *
FROM   (
  SELECT c.person_id,
         SUM(CASE c.payroll_time_type WHEN 'Regular Pay' THEN SUM(c.hours) END)
           OVER (PARTITION BY c.person_id) AS regular_pay,
         SUM(CASE c.payroll_time_type WHEN 'OT' THEN SUM(c.hours) END)
           OVER (PARTITION BY c.person_id) AS OT,
         SUM(c.hours) AS other_measure,
         c.payroll_time_type AS Other_code
  FROM   hwm_tm_rep_work_hours_sum_v c
         INNER JOIN per_all_people_f p
         ON (p.person_id = c.person_id)
  WHERE  grp_type_id = 200
  AND    payroll_time_type IN (
           'Afternoon shift',
           'TL',
           'Evening shift',
           'Regular Pay',
           'OT'
         )
  AND    c.start_time >= TRUNC(:from_date)
  AND    c.start_time <  TRUNC(:to_date) + INTERVAL '1' DAY
  GROUP BY
         c.person_id,
         c.payroll_time_type
)
WHERE   other_code NOT IN ('Regular Pay', 'OT');

其中,对于样本数据:

CREATE TABLE hwm_tm_rep_work_hours_sum_v (start_time, person_id, payroll_time_type, hours) AS
SELECT DATE '2021-01-01', 198, 'Regular Pay',     10 FROM DUAL UNION ALL
SELECT DATE '2021-01-01', 198, 'OT',               2 FROM DUAL UNION ALL
SELECT DATE '2021-01-01', 198, 'Afternoon shift',  2 FROM DUAL UNION ALL
SELECT DATE '2021-01-16', 198, 'Regular Pay',     10 FROM DUAL UNION ALL
SELECT DATE '2021-01-17', 198, 'OT',               3 FROM DUAL UNION ALL
SELECT DATE '2021-01-20', 198, 'Evening shift',    8 FROM DUAL UNION ALL
SELECT DATE '2021-01-08',  11, 'Regular Pay',      8 FROM DUAL UNION ALL
SELECT DATE '2021-01-09',  11, 'OT',               1 FROM DUAL UNION ALL
SELECT DATE '2021-01-08',  11, 'TL',               2 FROM DUAL UNION ALL
SELECT DATE '2021-01-10',  12, 'Evening shift',    9 FROM DUAL UNION ALL
SELECT DATE '2021-01-11',  12, 'Evening shift',    9 FROM DUAL;

CREATE TABLE per_all_people_f (person_id, grp_type_id) AS
SELECT 198, 200 FROM DUAL UNION ALL
SELECT  11, 200 FROM DUAL UNION ALL
SELECT  12, 200 FROM DUAL;

输出:

PERSON_ID REGULAR_PAY OT OTHER_MEASURE OTHER_CODE
11 8 1 2 TL
12 18 Evening shift
198 20 5 2 Afternoon shift
198 20 5 8 Evening shift

db小提琴here

【讨论】:

  • 当我使用精确查询时,other_measure 中 SUM(c.hours) 的计算不正确。它给了我除常规工资/OT 以外的所有其他列的总和
  • @Sree 请edit 使用minimal reproducible example 提出您的问题,包括您的表格的CREATE TABLE 语句;您的样本数据的INSERT 语句代表问题;以及您对该样本数据的预期输出。此查询生成您在问题中请求的确切输出;如果您的数据不同,那么您还没有提出具有代表性数据的问题,您希望我们如何提供解决您未向我们展示的问题的答案?
【解决方案2】:

您可以尝试这样的事情 - 不幸的是,在您的问题中,不清楚哪个表中哪些列/值可用。

SELECT 
  calc_time.person_id,
  (select sum(calc_time.start_time) FROM hwm_tm_rep_work_hours_sum_v calc_time where papf.person_id = calc_time.person_id and calc_time.payroll_time_type = 'Regular Pay') as Regular_Pay,
...
FROM   hwm_tm_rep_work_hours_sum_v calc_time,
       per_all_people_f papf
WHERE  grp_type_id = 200
AND    payroll_time_type IN ( 'Afternoon shift',
                             'TL',
                             'Evening shift',
                             'Regular Pay ',
                             'OT' )
AND    (
              To_date(To_char(calc_time.start_time, 'YYYY-MM-DD') , 'YYYY-MM-DD') BETWEEN To_date(To_char(:From_Date, 'YYYY-MM-DD'), 'YYYY-MM-DD')
              AND    To_date( To_char(:To_Date, 'YYYY-MM-DD'), 'YYYY-MM-DD' ) )
and  papf.person_id = calc_time.person_id

-- use a group by
GROUP BY
  calc_time.person_id

【讨论】:

    【解决方案3】:

    您可以使用聚合然后应用model 子句来计算所需的列。下面是 cmets 的代码,假设您可以按日期管理过滤器。

    select *
    from t
    
    PERSON_ID |元素 |措施 --------: | :---------------- | ------: 198 |定期工资 | 1 198 |定期工资 | 2 198 |下午班 | 3 198 |下午班 | 4 198 |旧约 | 5 198 |旧约 | 6 198 |夜班 | 7 198 |夜班 | 8 11 |定期工资 | 11 11 |定期工资 | 12 11 | TL | 13 11 | TL | 14 11 |夜班 | 15 11 |夜班 | 16 12 | TL | 21 12 | TL | 22 12 |夜班 | 23 12 |夜班 | 24
    select
      person_id,
      ot,
      regular_pay,
      elements as other_code,
      mes as other_measure
    from (
      /*First you need to aggregate all the measures by person_id and code*/
      select
        person_id,
        elements,
        sum(measure) as mes
      from t
      /*Date filter goes here*/
      group by
        person_id,
        elements
    )
    model
      /*RETURN UPDATED ROWS
       will do the trick,
      because we'll update only "other"
      measures, so OT and Regular pay will no go
      to the output*/
      return updated rows
      /*Where to break the calculation*/
      partition by (person_id)
      /*To be able to reference by code*/
      dimension by (elements)
      measures (
        mes,
        0 as ot,
        0 as regular_pay
      )
      rules upsert (
        ot[
          elements not in ('OT', 'Regular Pay')
        ] = sum(mes)['OT'],
        regular_pay[
          elements not in ('OT', 'Regular Pay')
        ] = sum(mes)['Regular Pay']
      )
    
    PERSON_ID |旧约 | REGULAR_PAY | OTHER_CODE | OTHER_MEASURE --------: | ---: | ----------: | :---------------- | ------------: 198 | 11 | 3 |夜班 | 15 198 | 11 | 3 |下午班 | 7 11 | | 23 | TL | 27 11 | | 23 |夜班 | 31 12 | | | TL | 43 12 | | |夜班 | 47

    db小提琴here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-25
      • 1970-01-01
      • 2013-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多