【发布时间】:2021-08-06 13:09:12
【问题描述】:
我在下面有一个测试用例,它工作正常。在第一个场景中,我重复使用 TRUC(access_date) 以便分组正常工作。
我想只使用一次子查询来执行 TRUNC(access_date) 以使代码更清晰,并且只在一个地方执行 TRUNC 命令,但我很难让它工作。
谁能告诉我如何解决这个问题。我提供了工作版本和我的尝试,但我无法工作。
ALTER SESSION SET NLS_DATE_FORMAT = 'MMDDYYYY HH24:MI:SS';
CREATE OR REPLACE TYPE nt_date IS TABLE OF DATE;
/
CREATE OR REPLACE FUNCTION generate_dates_pipelined(
p_from IN DATE,
p_to IN DATE
)
RETURN nt_date PIPELINED DETERMINISTIC
IS
v_start DATE := TRUNC(LEAST(p_from, p_to));
v_end DATE := TRUNC(GREATEST(p_from, p_to));
BEGIN
LOOP
PIPE ROW (v_start);
EXIT WHEN v_start >= v_end;
v_start := v_start + INTERVAL '1' DAY;
END LOOP;
RETURN;
END generate_dates_pipelined;
/
create table employees(
employee_id NUMBER(6),
first_name VARCHAR2(20),
last_name VARCHAR2(20),
card_num VARCHAR2(10),
work_days VARCHAR2(7)
);
ALTER TABLE employees
ADD (
CONSTRAINT employees_pk PRIMARY KEY (employee_id)
);
INSERT INTO employees (
EMPLOYEE_ID,
first_name,
last_name,
card_num,
work_days
)
WITH names AS (
SELECT 1, 'Jane', 'Doe', 'F123456', 'NYYYYYN' FROM dual UNION ALL
SELECT 2, 'Madison', 'Smith', 'R33432','NYYYYYN' FROM dual UNION ALL
SELECT 3, 'Justin', 'Case', 'C765341','NYYYYYN' FROM dual UNION ALL
SELECT 4, 'Mike', 'Jones', 'D564311','NYYYYYN' FROM dual )
SELECT * FROM names;
CREATE TABLE locations AS
SELECT level AS location_id,
'Door ' || level AS location_name,
CASE round(dbms_random.value(1,3))
WHEN 1 THEN 'A'
WHEN 2 THEN 'T'
WHEN 3 THEN 'T'
END AS location_type
FROM dual
CONNECT BY level <= 3;
ALTER TABLE locations
ADD ( CONSTRAINT locations_pk
PRIMARY KEY (location_id));
create table access_history(
seq_num integer GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
employee_id NUMBER(6),
card_num varchar2(10),
location_id number(4),
access_date date,
processed NUMBER(1) default 0
);
create or replace procedure create_access_history(p_start_date date, p_end_date date)
IS
BEGIN
INSERT into access_history
(
employee_id,
card_num,
location_id,
access_date
)
WITH cntr AS
(
SELECT LEVEL - 1 AS n
FROM dual
CONNECT BY LEVEL <= 15 -- Max number of rows per employee per date
)
, got_location_num AS
(
SELECT location_id
, ROW_NUMBER () OVER (ORDER BY location_id) AS location_num
, COUNT (*) OVER () AS max_location_num
FROM locations
)
, employee_days AS
(
SELECT e.employee_id, e.card_num
, d.column_value AS access_date
, dbms_random.value (0, 15) AS rn -- 0 to max number of rows per employee per date
FROM employees e
CROSS JOIN TABLE (generate_dates_pipelined (p_start_date, p_end_date)) d
)
, employee_n_days AS
(
SELECT ed.employee_id, ed.card_num, ed.access_date
, dbms_random.value (0, 1) AS lrn
FROM employee_days ed
JOIN cntr c ON c.n <= ed.rn
)
SELECT n.employee_id, n.card_num, l.location_id,
n.access_date + NUMTODSINTERVAL(FLOOR(DBMS_RANDOM.VALUE(0,86399)), 'SECOND')
FROM employee_n_days n
JOIN got_location_num l ON l.location_num = CEIL (n.lrn * l.max_location_num);
END;
EXEC create_access_history (DATE '2021-08-06', DATE '2021-08-11');
-- Works
select TRUNC(a. access_date) access_date,
e.employee_id,
count(*) cnt
FROM employees e
JOIN access_history a ON a.employee_id = e.employee_id
JOIN locations l ON l.location_id = a.location_id
GROUP BY GROUPING SETS (
(TRUNC(a.access_date), e.employee_id),
(trunc(a.access_date)),
()
)
ORDER BY trunc(a. access_date),e.employee_id;
固定
选择
访问日期,
员工ID,
数数(*)
从
(
选择 TRUNC(a.access_date) 作为 access_date,
e.employee_id
来自员工 e
JOIN access_history a ON a.employee_id = e.employee_id
加入位置 l ON l.location_id = a.location_id ) ah_trunc
按分组集分组(
(access_date, employee_id),
(访问日期),
()
)
ORDER BY access_date,employee_id;
【问题讨论】:
-
我并没有完全理解,但是在您的最终查询中,ah_trunc 有两列名为
"TRUNC(a.access_date)"和employee_id,这就是为什么您不能从中选择access_date的原因(如果这就是“不起作用”的意思)。尝试给第一个别名。 -
好的,所以如果您按照我的建议修复错字(
JOIN locations l.之后的杂散点)和别名TRUNC(a.access_date),则您的原始示例有效。我不确定你需要 150 行代码来演示它。