英文:
Query that returns the count of all distinct days between multiple start and end dates
问题
我将为您提供代码的翻译:
-- 查询每辆车的行程天数,排除重复的天数
SELECT
v.id_vehicle,
v.model,
COUNT(DISTINCT TO_DATE(t.dt_start, 'DD-MM-YYYY')) AS qtd_days
FROM
tb_vehicle v
JOIN
tb_trip t
ON
v.id_vehicle = t.id_vehicle
GROUP BY
v.id_vehicle,
v.model;
请注意,这是一个SQL查询,用于从ORACLE数据库中的两个表('tb_vehicle'和'tb_trip')中获取每辆车的行程天数。查询排除了重复的天数,只计算每辆车出行的不同日期。
英文:
I'm going to simplify the basis for asking the question. I have two tables in the ORACLE database: one called 'tb_vehicle' (id_vehicle, model, ...) and another table 'tb_trip' (id_vehicle, dt_start, dt_end, ...).
I am not able to carry out a query that returns the number of days that each vehicle was on the trip, excluding the repeated days (what do you mean? in the same day a vehicle can leave 1, 2, 3, ... times, however, I just need to know that the vehicle left on the day and not the number of times it left [I already made this query for another chart and it was very quiet]).
Example:
tb_vehicle
id_vehicle | model |
---|---|
1 | Chevrolet Cruze |
2 | Chevrolet Sonic |
tb_trip
id_vehicle | dt_start | dt_end |
---|---|---|
1 | 06-05-2023 | 06-05-2023 |
1 | 06-05-2023 | 06-05-2023 |
1 | 06-05-2023 | 06-08-2023 |
2 | 06-05-2023 | 06-06-2023 |
OBS: I am ignoring in this example the hours and minutes
intended result:
id_vehicle | model | qtd_days |
---|---|---|
1 | Chevrolet Cruze | 4 |
2 | Chevrolet Sonic | 2 |
I was able to count the individual statistics for each vehicle using PL/SQL. But I need to perform this query only with SQL.
The system is developed at APEX.
答案1
得分: 1
以下是翻译好的部分:
这是一种选项。
示例数据:
SQL> with
2 tb_vehicle (id_vehicle, model) as
3 (select 1, 'Chevrolet Cruze' from dual union all
4 select 2, 'Chevrolet Sonic' from dual
5 ),
6 tb_trip (id_vehicle, dt_start, dt_end) as
7 (select 1, date '2023-06-05', date '2023-06-05' from dual union all
8 select 1, date '2023-06-05', date '2023-06-05' from dual union all
9 select 1, date '2023-06-05', date '2023-06-08' from dual union all
10 select 2, date '2023-06-05', date '2023-06-06' from dual
11 ),
查询从这里开始; `temp` CTE 列出了开始日期和结束日期之间的所有日期; 最终查询计算了每辆车的不同日期(以及与 `tb_vehicle` 表的连接):
12 temp as
13 (select t.id_vehicle, t.dt_start + column_value - 1 datum
14 from tb_trip t cross join
15 table(cast(multiset(select level from dual
16 connect by level <= dt_end - dt_start + 1
17 ) as sys.odcinumberlist))
18 )
19 select a.id_vehicle, m.model, count(distinct a.datum) qtd_Days
20 from temp a join tb_vehicle m on m.id_vehicle = a.id_vehicle
21 group by a.id_Vehicle, m.model
22 order by a.id_Vehicle;
ID_VEHICLE MODEL QTD_DAYS
---------- --------------- ----------
1 Chevrolet Cruze 4
2 Chevrolet Sonic 2
SQL>;
英文:
Here's one option.
Sample data:
SQL> with
2 tb_vehicle (id_vehicle, model) as
3 (select 1, 'Chevrolet Cruze' from dual union all
4 select 2, 'Chevrolet Sonic' from dual
5 ),
6 tb_trip (id_vehicle, dt_start, dt_end) as
7 (select 1, date '2023-06-05', date '2023-06-05' from dual union all
8 select 1, date '2023-06-05', date '2023-06-05' from dual union all
9 select 1, date '2023-06-05', date '2023-06-08' from dual union all
10 select 2, date '2023-06-05', date '2023-06-06' from dual
11 ),
Query begins here; temp
CTE lists all dates between start and end date; the final query calculates distinct dates per vehicle (along with join to tb_vehicle
table):
12 temp as
13 (select t.id_vehicle, t.dt_start + column_value - 1 datum
14 from tb_trip t cross join
15 table(cast(multiset(select level from dual
16 connect by level <= dt_end - dt_start + 1
17 ) as sys.odcinumberlist))
18 )
19 select a.id_vehicle, m.model, count(distinct a.datum) qtd_Days
20 from temp a join tb_vehicle m on m.id_vehicle = a.id_vehicle
21 group by a.id_Vehicle, m.model
22 order by a.id_Vehicle;
ID_VEHICLE MODEL QTD_DAYS
---------- --------------- ----------
1 Chevrolet Cruze 4
2 Chevrolet Sonic 2
SQL>
答案2
得分: 1
这是Littlefoot的想法,使用了稍微不同的查询。我正在使用标准的递归CTE来首先生成行中的单个日期。然后,我计算每辆车的不同日期数。最后,我将此结果与车辆表连接。您可能会发现这个查询稍微容易理解。
with single_days(id_vehicle, dt, dt_end) as
(
select id_vehicle, dt_start, dt_end from tb_trip
union all
select id_vehicle, dt + 1, dt_end from single_days where dt < dt_end
)
, counted_days as
(
select id_vehicle, count(distinct dt) as days
from single_days
group by id_vehicle
)
select *
from tb_vehicle v
join counted_days c using (id_vehicle);
演示链接:https://dbfiddle.uk/paJKama3
英文:
Here is Littlefoot's idea with a slightly different query. I am using a standard recursive CTE to generate the single days from the rows first. Then I count the distinct days per vehicle. At last I join this result to the vehicle table. You may find this query a tad easier to understand.
with single_days(id_vehicle, dt, dt_end) as
(
select id_vehicle, dt_start, dt_end from tb_trip
union all
select id_vehicle, dt + 1, dt_end from single_days where dt < dt_end
)
, counted_days as
(
select id_vehicle, count(distinct dt) as days
from single_days
group by id_vehicle
)
select *
from tb_vehicle v
join counted_days c using (id_vehicle);
答案3
得分: 1
以下是您提供的内容的翻译:
生成所有日期的列表,然后查找不同的日期很容易编码,但如果范围很大,那么成本会很高。
相反,您可以合并范围(通过“UNPIVOT”日期,然后使用“MATCH_RECOGNIZE”合并重叠),然后使用算术来计算范围的大小,并对每辆车进行聚合:
SELECT v.id_vehicle,
MAX(v.model) AS model,
SUM(t.dt_end - t.dt_start + 1) AS qtd_days
FROM tb_trip
UNPIVOT (
dt FOR type IN (dt_start AS 1, dt_end AS -1)
)
MATCH_RECOGNIZE(
PARTITION BY id_vehicle
ORDER BY dt, type DESC
MEASURES
FIRST(dt) AS dt_start,
LAST(dt) AS dt_end
PATTERN ( overlaps+ range_end )
DEFINE
overlaps AS SUM(type) > 0,
range_end AS SUM(type) = 0
) t
INNER JOIN tb_vehicle v
ON (t.id_vehicle = v.id_vehicle)
GROUP BY v.id_vehicle
对于示例数据:
CREATE TABLE tb_vehicle (id_vehicle, model) AS
SELECT 1, 'Chevrolet Cruze' FROM DUAL UNION ALL
SELECT 2, 'Chevrolet Sonic' FROM DUAL UNION ALL
SELECT 3, 'DeLorean' FROM DUAL;
CREATE TABLE tb_trip (id_vehicle, dt_start, dt_end) AS
SELECT 1, DATE '2023-06-05', DATE '2023-06-05' FROM DUAL UNION ALL
SELECT 1, DATE '2023-06-05', DATE '2023-06-05' FROM DUAL UNION ALL
SELECT 1, DATE '2023-06-05', DATE '2023-06-08' FROM DUAL UNION ALL
SELECT 2, DATE '2023-06-05', DATE '2023-06-06' FROM DUAL UNION ALL
SELECT 3, DATE '1885-01-01', DATE '9999-12-31' FROM DUAL;
输出:
ID_VEHICLE | MODEL | QTD_DAYS |
---|---|---|
1 | Chevrolet Cruze | 4 |
2 | Chevrolet Sonic | 2 |
3 | DeLorean | 2963942 |
英文:
Generating a list of all the days and then finding the distinct days is simple to code but if you have large ranges then it will become costly.
Instead you can merge the ranges (by UNPIVOT
ing the dates and then using MATCH_RECOGNIZE
to merge the overlaps) and then using arithmetic to calculate the size of the range and aggregating for each vehicle:
SELECT v.id_vehicle,
MAX(v.model) AS model,
SUM(t.dt_end - t.dt_start + 1) AS qtd_days
FROM tb_trip
UNPIVOT (
dt FOR type IN (dt_start AS 1, dt_end AS -1)
)
MATCH_RECOGNIZE(
PARTITION BY id_vehicle
ORDER BY dt, type DESC
MEASURES
FIRST(dt) AS dt_start,
LAST(dt) AS dt_end
PATTERN ( overlaps+ range_end )
DEFINE
overlaps AS SUM(type) > 0,
range_end AS SUM(type) = 0
) t
INNER JOIN tb_vehicle v
ON (t.id_vehicle = v.id_vehicle)
GROUP BY v.id_vehicle
Which, for the sample data:
CREATE TABLE tb_vehicle (id_vehicle, model) AS
SELECT 1, 'Chevrolet Cruze' FROM DUAL UNION ALL
SELECT 2, 'Chevrolet Sonic' FROM DUAL UNION ALL
SELECT 3, 'DeLorean' FROM DUAL;
CREATE TABLE tb_trip (id_vehicle, dt_start, dt_end) AS
SELECT 1, DATE '2023-06-05', DATE '2023-06-05' FROM DUAL UNION ALL
SELECT 1, DATE '2023-06-05', DATE '2023-06-05' FROM DUAL UNION ALL
SELECT 1, DATE '2023-06-05', DATE '2023-06-08' FROM DUAL UNION ALL
SELECT 2, DATE '2023-06-05', DATE '2023-06-06' FROM DUAL UNION ALL
SELECT 3, DATE '1885-01-01', DATE '9999-12-31' FROM DUAL;
Outputs:
ID_VEHICLE | MODEL | QTD_DAYS |
---|---|---|
1 | Chevrolet Cruze | 4 |
2 | Chevrolet Sonic | 2 |
3 | DeLorean | 2963942 |
答案4
得分: 0
我希望下面的代码能够满足您的需求:
select v.id
,v.model
,sum(case when DT_END<>DT_START then DT_END - DT_START + 1 else 0 end) qtd_days
from tb_trip t,
tb_vehicle v
where t.id_vehicle = v.id
group by v.id ,v.model
order by v.id
注意:此代码是SQL查询,用于从名为"tb_trip"和"tb_vehicle"的表中检索数据,并按照"v.id"进行分组和排序。
英文:
I hope the code below can meet your need :
select v.id
,v.model
,sum(case when DT_END<>DT_START then DT_END - DT_START + 1 else 0 end) qtd_days
from tb_trip t,
tb_vehicle v
where t.id_vehicle = v.id
group by v.id ,v.model
order by v.id
答案5
得分: 0
Here's the translation of the code snippet you provided:
使用MATCH_RECOGNIZE的简化版本
with tb_trip(id_vehicle, dt_start, dt_end) as (
select 1, to_date('06-05-2023', 'mm-dd-yyyy'), to_date('06-05-2023', 'mm-dd-yyyy') from dual union all
select 1, to_date('06-05-2023', 'mm-dd-yyyy'), to_date('06-05-2023', 'mm-dd-yyyy') from dual union all
select 1, to_date('06-05-2023', 'mm-dd-yyyy'), to_date('06-08-2023', 'mm-dd-yyyy') from dual union all
select 2, to_date('06-05-2023', 'mm-dd-yyyy'), to_date('06-06-2023', 'mm-dd-yyyy') from dual -- union all
),
tb_vehicle(id_vehicle, model) as (
select 1, 'Chevrolet Cruze' from dual union all
select 2, 'Chevrolet Sonic' from dual
)
select d.id_vehicle, v.model, sum(dt_end - dt_start +1) as days
from (
select * from tb_trip
match_recognize (
partition by id_vehicle
order by dt_start, dt_end
measures first(dt_start) as dt_start, max(dt_end) as dt_end
pattern( overlaps* strt )
define
overlaps as dt_end >= dt_start
)
) d
join tb_vehicle v on v.id_vehicle = d.id_vehicle
group by d.id_vehicle, v.model
;
Please note that I've only translated the code part as per your request.
英文:
Simpler version using MATCH_RECOGNIZE
with tb_trip(id_vehicle, dt_start, dt_end) as (
select 1, to_date('06-05-2023', 'mm-dd-yyyy'), to_date('06-05-2023', 'mm-dd-yyyy') from dual union all
select 1, to_date('06-05-2023', 'mm-dd-yyyy'), to_date('06-05-2023', 'mm-dd-yyyy') from dual union all
select 1, to_date('06-05-2023', 'mm-dd-yyyy'), to_date('06-08-2023', 'mm-dd-yyyy') from dual union all
select 2, to_date('06-05-2023', 'mm-dd-yyyy'), to_date('06-06-2023', 'mm-dd-yyyy') from dual -- union all
),
tb_vehicle(id_vehicle, model) as (
select 1, 'Chevrolet Cruze' from dual union all
select 2, 'Chevrolet Sonic' from dual
)
select d.id_vehicle, v.model, sum(dt_end - dt_start +1) as days
from (
select * from tb_trip
match_recognize (
partition by id_vehicle
order by dt_start, dt_end
measures first(dt_start) as dt_start, max(dt_end) as dt_end
pattern( overlaps* strt )
define
overlaps as dt_end >= dt_start
)
) d
join tb_vehicle v on v.id_vehicle = d.id_vehicle
group by d.id_vehicle, v.model
;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论