重新生成sql查询以从两个表求和日期

重新生成sql查询以从两个表求和日期,sql,firebird,Sql,Firebird,我需要一个解决方案扩展,我收到的,它是在链接可见。我无法连接两个表中的数据。我有两个表KP和KPS中的日期数据。我知道我必须从SQL查询中的第二个表中添加数据,在那个地方是KP2的定义,但我不知道如何做到这一点。我应该使用join吗 我有一个SQL查询: SELECT KP3.id_contact, (KP3.D2-KP3.D1) / (12*31) AS Y, ((KP3.D2-KP3.D1) - ((KP3.D2-KP3.D1) / (12*31)) * 12 * 3

我需要一个解决方案扩展,我收到的,它是在链接可见。我无法连接两个表中的数据。我有两个表KP和KPS中的日期数据。我知道我必须从SQL查询中的第二个表中添加数据,在那个地方是KP2的定义,但我不知道如何做到这一点。我应该使用join吗

我有一个SQL查询:

SELECT
    KP3.id_contact,
    (KP3.D2-KP3.D1) / (12*31) AS Y,
    ((KP3.D2-KP3.D1) - ((KP3.D2-KP3.D1) / (12*31)) * 12 * 31) / 31 AS M,
    CAST(MOD((KP3.D2-KP3.D1) - (((KP3.D2-KP3.D1) / (12*31)) * 12 * 31), 31) AS INTEGER) AS D
FROM
    (SELECT
         KP2.id_contact, SUM(KP2.D1) AS D1, SUM(KP2.D2) AS D2
     FROM
         (SELECT
              KP.id_contact, 
              DATEDIFF(MONTH, KP.DATE_FROM, KP.DATE_TO) / 12 AS Y, 
              CAST(MOD(DATEDIFF(MONTH, KP.DATE_FROM, KP.DATE_TO), 12) AS INTEGER) AS M,
              EXTRACT(YEAR FROM KP.DATE_FROM)*12*31+EXTRACT(MONTH FROM KP.DATE_FROM)*31+EXTRACT(DAY FROM KP.DATE_FROM) D1,
              EXTRACT(YEAR FROM KP.DATE_TO)*12*31+EXTRACT(MONTH FROM KP.DATE_TO)*31+EXTRACT(DAY FROM KP.DATE_TO) D2 
          FROM
              KP) AS KP2
    GROUP BY 
        KP2.id_contact) AS KP3
我在示例中展示了这一点。表KP中有如下数据

ID    DATE_FROM    DATE_TO
------------------------------
1     2018-02-08   2019-12-01
在表KPS中,我有如下数据:

ID    DATE_FROM    DATE_TO
------------------------------
1     2017-02-20   2018-01-01
2Y 8M 7D
查询结果应如下所示:

ID    DATE_FROM    DATE_TO
------------------------------
1     2017-02-20   2018-01-01
2Y 8M 7D

请帮我做这个。

可能是这样的:

DROP TABLE IF EXISTS #TestTableA, #TestTableB
CREATE TABLE #TestTableA (DFA DATE, DTA DATE)
CREATE TABLE #TestTableB (DFB DATE, DTB DATE)

INSERT INTO #TestTableA
SELECT '2018-02-08','2019-12-01'

INSERT INTO #TestTableB
SELECT '2017-02-20','2018-01-01'

SELECT  CAST(SUM(DaysQTY) / 365 AS VARCHAR(4)) + 'Y ' +
        CAST((SUM(DaysQTY) % 365) / 30 AS VARCHAR(2)) + 'M ' +
        CAST((SUM(DaysQTY) % 365) % 30 AS VARCHAR(2)) + 'D' AS Result
FROM    (   SELECT  DATEDIFF(DAY,DFA,DTA) AS DaysQTY
            FROM    #TestTableA
            UNION   ALL
            SELECT  DATEDIFF(DAY,DFB,DTB) AS DaysQTY
            FROM    #TestTableB
        )   t

试着猜你的意思

也许您的意思是在所有源表之间选择最早的最小日期,然后选择最晚的日期并计算其间的天数

或者,您可能想计算所有源表中每个作业的天数,以及nsum中每个工人的天数

不知道,这两种解决方案都是从简单的模块进一步构建而成,并进一步扩展到最终结果。它还使用您链接的问题中的数据进行自我检查

以下是您可以调整的脚本,看看它是如何运行的:

结果可能是2年9个月2天,也可能是2年8个月1天,这取决于您对加入源表的含义的猜测

Cherry选择您需要的子查询并剔除不需要的子查询


您需要以何种方式连接表KP和KPS中的数据?这里的逻辑是什么?为什么这种组合会导致2Y 8M 7D?这在Firebird中完全不行。如果存在该下拉表并选择“2017-02-20”,“2018-01-01”就是非标准SQL。还有,到底为什么要使用select中的insert而不是标准的insert来插入tx、y、z值xxx、yyy、zzz,我想知道…@Arioch'The:更糟糕的是:+不用于连接SQL中的字符串-其运算符是| | | a| u horse_,带有_no_名称,我甚至没有查看运算符,或者可能我也会注意到C样式的%表示余数:-D
-- https://stackoverflow.com/questions/60030543/rebuild-sql-query-to-sum-date-from-two-tables

create table KPS1 (
  ID integer not null,
  DATE_FROM date not null,
  DATE_TO date not null
)
create table KPS2 (
  ID integer not null,
  DATE_FROM date not null,
  DATE_TO date not null
)
create index KPS1_workers on KPS1(id)
create index KPS2_workers on KPS2(id)
insert into KPS1 values (1, '2018-02-08', '2019-12-01')
1 rows affected
insert into KPS2 values (1, '2017-02-20', '2018-01-01')
1 rows affected
-- this data sample taked from
-- https://stackoverflow.com/questions/51551257/how-to-get-correct-year-month-and-day-in-firebird-function-datediff
insert into KPS1 values (2, '1988-09-15', '2000-03-16')
1 rows affected
insert into KPS1 values (2, '2000-03-16', '2005-02-28')
1 rows affected
select * from KPS1 union all select * from KPS2
ID | DATE_FROM | DATE_TO -: | :--------- | :--------- 1 | 2018-02-08 | 2019-12-01 2 | 1988-09-15 | 2000-03-16 2 | 2000-03-16 | 2005-02-28 1 | 2017-02-20 | 2018-01-01
-- sadly, the topic starter did not say what he wants to do with his many sources of data
-- so multiple interpretations are possible!

-- here we are counting days from the first date to the last date, one row per worker

-- finding the minimum and maximum dates from ALL the sources
--  (multitude of rows in multitude of tables)
-- very simple to write and read, it however would be bad on long tables
-- because ID indexes hidden by UNION and not available for further, outer queries
--   FULL-SCAN in natural order and post-merge external sorting would occur

Select ID as id_contact, Min(DATE_FROM) as DATE_FROM, Max(DATE_TO) as DATE_TO
From (select * from KPS1 union all select * from KPS2)
Group by ID
ID_CONTACT | DATE_FROM | DATE_TO ---------: | :--------- | :--------- 1 | 2017-02-20 | 2019-12-01 2 | 1988-09-15 | 2005-02-28
-- finding the minimum and maximum dates from ALL the sources
-- this one is harder to write and read
-- but should be better for execution: it allows use of indexes by ID be propagated

-- This optimized query works fine with the data presented by topic starter
-- where each source tables has exactly one row for one and the same worker.

-- It will not work so fine when some workers are missed from some tables.
-- Fixing it will make the query even more complex to write and read

Select KPS1.ID as id_contact, 
  IIF(KPS1.DATE_FROM < KPS2.DATE_FROM, KPS1.DATE_FROM, KPS2.DATE_FROM) as DATE_FROM,
  IIF(KPS2.DATE_TO < KPS2.DATE_TO, KPS2.DATE_TO, KPS1.DATE_TO) as DATE_TO
From KPS1, KPS2
Where KPS1.ID = KPS2.ID
ID_CONTACT | DATE_FROM | DATE_TO ---------: | :--------- | :--------- 1 | 2017-02-20 | 2019-12-01
Select ID_CONTACT, DateDiff(day, DATE_FROM, DATE_TO) as DAYS_COUNT From
(
  Select ID as id_contact, Min(DATE_FROM) as DATE_FROM, Max(DATE_TO) as DATE_TO
  From (select * from KPS1 union all select * from KPS2)
  Group by ID
)
ID_CONTACT | DAYS_COUNT ---------: | :--------- 1 | 1014 2 | 6010
-- alternatively, here counting days per-job, many rows may happen for the same worker

select a.*, datediff(day, a.DATE_FROM, a.DATE_TO) as DAYS_COUNT from KPS1 a
  union all
select b.*, datediff(day, b.DATE_FROM, b.DATE_TO) as DAYS_COUNT from KPS2 b
ID | DATE_FROM | DATE_TO | DAYS_COUNT -: | :--------- | :--------- | :--------- 1 | 2018-02-08 | 2019-12-01 | 661 2 | 1988-09-15 | 2000-03-16 | 4200 2 | 2000-03-16 | 2005-02-28 | 1810 1 | 2017-02-20 | 2018-01-01 | 315
SELECT ID as ID_CONTACT, SUM(Days_Count) as DAYS_COUNT FROM
(
  select a.*, datediff(day, a.DATE_FROM, a.DATE_TO) as DAYS_COUNT from KPS1 a 
) 
GROUP BY ID_CONTACT

    union all

SELECT ID as ID_CONTACT, SUM(Days_Count) as DAYS_COUNT FROM
(
  select b.*, datediff(day, b.DATE_FROM, b.DATE_TO) as DAYS_COUNT from KPS2 b
)  
GROUP BY ID_CONTACT
ID_CONTACT | DAYS_COUNT ---------: | :--------- 1 | 661 2 | 6010 1 | 315
WITH PER_SOURCE_SUMMER AS 
(
  SELECT ID as ID_CONTACT, SUM(Days_Count) as DAYS_COUNT FROM
  (
    select a.*, datediff(day, a.DATE_FROM, a.DATE_TO) as DAYS_COUNT from KPS1 a 
  ) 
  GROUP BY ID_CONTACT

    union all

  SELECT ID as ID_CONTACT, SUM(Days_Count) as DAYS_COUNT FROM
  (
    select b.*, datediff(day, b.DATE_FROM, b.DATE_TO) as DAYS_COUNT from KPS2 b
  )  
  GROUP BY ID_CONTACT
)

SELECT ID_CONTACT, SUM(Days_Count) as DAYS_COUNT 
FROM PER_SOURCE_SUMMER
GROUP BY 1
ID_CONTACT | DAYS_COUNT ---------: | :--------- 1 | 976 2 | 6010
-- Now, having TWO interpretations of the task and TWO implementations of days counter
-- we finally can come up with conversion from precise but hard to feel DAYS 
-- to imprecise but easy to digest Y-M-D

WITH SOURCE_MIN_MAX AS
(
  Select ID_CONTACT, DateDiff(day, DATE_FROM, DATE_TO) as DAYS_COUNT From
  (
    Select ID as id_contact, Min(DATE_FROM) as DATE_FROM, Max(DATE_TO) as DATE_TO
    From (select * from KPS1 union all select * from KPS2)
    Group by ID
  )
),

PER_SOURCE_SUMMER AS 
(
  SELECT ID as ID_CONTACT, SUM(Days_Count) as DAYS_COUNT FROM
  (
    select a.*, datediff(day, a.DATE_FROM, a.DATE_TO) as DAYS_COUNT from KPS1 a 
  ) 
  GROUP BY ID_CONTACT

    union all

  SELECT ID as ID_CONTACT, SUM(Days_Count) as DAYS_COUNT FROM
  (
    select b.*, datediff(day, b.DATE_FROM, b.DATE_TO) as DAYS_COUNT from KPS2 b
  )  
  GROUP BY ID_CONTACT
),

SOURCE_PER_JOB AS
(
  SELECT ID_CONTACT, SUM(Days_Count) as DAYS_COUNT 
  FROM PER_SOURCE_SUMMER
  GROUP BY 1
),

KP_DAYS AS
(
  SELECT 1 as METHOD, A.* FROM SOURCE_MIN_MAX A
     union all
  SELECT 2 as METHOD, B.* FROM SOURCE_PER_JOB B
)

SELECT * from KP_DAYS
METHOD | ID_CONTACT | DAYS_COUNT -----: | ---------: | :--------- 1 | 1 | 1014 1 | 2 | 6010 2 | 1 | 976 2 | 2 | 6010
WITH SOURCE_MIN_MAX AS
(
  Select ID_CONTACT, DateDiff(day, DATE_FROM, DATE_TO) as DAYS_COUNT From
  (
    Select ID as id_contact, Min(DATE_FROM) as DATE_FROM, Max(DATE_TO) as DATE_TO
    From (select * from KPS1 union all select * from KPS2)
    Group by ID
  )
),

PER_SOURCE_SUMMER AS 
(
  SELECT ID as ID_CONTACT, SUM(Days_Count) as DAYS_COUNT FROM
  (
    select a.*, datediff(day, a.DATE_FROM, a.DATE_TO) as DAYS_COUNT from KPS1 a 
  ) 
  GROUP BY ID_CONTACT

    union all

  SELECT ID as ID_CONTACT, SUM(Days_Count) as DAYS_COUNT FROM
  (
    select b.*, datediff(day, b.DATE_FROM, b.DATE_TO) as DAYS_COUNT from KPS2 b
  )  
  GROUP BY ID_CONTACT
),

SOURCE_PER_JOB AS
(
  SELECT ID_CONTACT, SUM(Days_Count) as DAYS_COUNT 
  FROM PER_SOURCE_SUMMER
  GROUP BY 1
),

KP_DAYS AS
(
  SELECT 1 as METHOD, A.* FROM SOURCE_MIN_MAX A
     union all
  SELECT 2 as METHOD, B.* FROM SOURCE_PER_JOB B
)

SELECT
    KP_DAYS.method, KP_DAYS.id_contact, KP_DAYS.days_count,
    FLOOR(KP_DAYS.DAYS_COUNT / 365.25) AS Y
  , FLOOR( (KP_DAYS.DAYS_COUNT - (FLOOR(KP_DAYS.DAYS_COUNT / 365.25) * 365.25) ) / 30.5) AS M 
  , CAST(MOD((KP_DAYS.DAYS_COUNT) - (((KP_DAYS.DAYS_COUNT) / 365.25) * 365.25), 30.5) AS INTEGER) AS D
FROM KP_DAYS
METHOD | ID_CONTACT | DAYS_COUNT | Y | M | D -----: | ---------: | :--------- | :- | :- | -: 1 | 1 | 1014 | 2 | 9 | 2 1 | 2 | 6010 | 16 | 5 | 2 2 | 1 | 976 | 2 | 8 | 1 2 | 2 | 6010 | 16 | 5 | 2