0

我有以下问题,因为不知道如何解决这个问题:

我有下表

Column
------
04/2013
07/2013
12/2013
07/2014
12/2014
07/2015
12/2015
07/2016
12/2016
07/2017
12/2017
07/2018
12/2018
07/2019
12/2019
07/2020
08/2020

我想从这张表中得到另一张表,其中包含这样的“句点”:

Start  End
04/2013 06/2013
07/2013 11/2013
12/2013 06/2014
07/2014 11/2014
12/2014 06/2015
07/2015 11/2015
12/2015 06/2016
07/2016 11/2016
12/2016 06/2017
07/2017 11/2017
12/2017 06/2018
07/2018 11/2018
12/2018 06/2019
07/2019 11/2019
12/2019 06/2020
07/2020 08/2020

其中源表的第一行是期间的开始,源表的最后一行是期间的结束,第二个所需表的第二列是减少以下开始日期的一个月源表中的行。

我不想使用任何游标或类似的东西,只是询问是否有任何方法可以执行 sql 查询。

4

2 回答 2

0

你似乎想要LEAD()。诀窍是修改日期以减去一个月。我假设该列实际上是一个日期。

在标准 SQL 中,这看起来像:

select col,
       lead(col) over (order by col) - interval '1 month'
from t;

请注意,这包括带有NULL第二列值的最后一行。这对我来说似乎是一个功能,但您可以将上述内容用作子查询并过滤掉该NULL值。

编辑:

在不受支持的 SQL Server 版本中,您可以使用横向连接或子查询:

select col,
       (select dateadd(month, 1, min(col)) 
        from t t2
        where t2.col > t.col
       ) 
from t;
于 2020-08-14T12:24:36.643 回答
0

要执行日期算术,您应该将年月字面量转换为月份的第一个日期字面量,如下所示。我还让您选择按月或按天与继任者不同。以及在目标表中包含字符串或 DATE 类型的选择。

CREATE TABLE output AS
WITH 
-- your input
input (col) AS (
          SELECT '04/2013'
UNION ALL SELECT '07/2013'
UNION ALL SELECT '12/2013'
UNION ALL SELECT '07/2014'
UNION ALL SELECT '12/2014'
UNION ALL SELECT '07/2015'
UNION ALL SELECT '12/2015'
UNION ALL SELECT '07/2016'
UNION ALL SELECT '12/2016'
UNION ALL SELECT '07/2017'
UNION ALL SELECT '12/2017'
UNION ALL SELECT '07/2018'
UNION ALL SELECT '12/2018'
UNION ALL SELECT '07/2019'
UNION ALL SELECT '12/2019'
UNION ALL SELECT '07/2020'
UNION ALL SELECT '08/2020'
)
,
-- need to convert to DATE type to sort properly
todate AS (
  SELECT
    col
  , TO_DATE(col,'MM/YYYY') AS dt
  FROM input
)
-- remove the cols you don't need, but it will 
-- be handy to have them all as DATES
-- I'll also add a more convenient col, ony 1 day before the next
,
one_row_too_many AS (
  SELECT
    col                                                           AS start_string
  , dt                                                            AS start_dt
  , LEAD(dt) OVER(ORDER BY dt) - 1                                AS end_dt_by_day
  , TO_CHAR(LEAD(dt) OVER(ORDER BY dt) - 1,'MM/YYYY')             AS end_string_by_day
  , CAST(LEAD(dt) OVER(ORDER BY dt) - INTERVAL '1 MONTH' AS DATE) AS end_dt_by_month
  FROM todate
)
SELECT 
  * 
FROM 
one_row_too_many
WHERE end_dt_by_day IS NOT NULL;

-- CONTROL QUERY
SELECT * FROM output;
-- out Time: First fetch (0 rows): 51.357 ms. All rows formatted: 51.364 ms
-- out  start_string |  start_dt  | end_dt_by_day | end_string_by_day | end_dt_by_month 
-- out --------------+------------+---------------+-------------------+-----------------
-- out  04/2013      | 2013-04-01 | 2013-06-30    | 06/2013           | 2013-06-01
-- out  07/2013      | 2013-07-01 | 2013-11-30    | 11/2013           | 2013-11-01
-- out  07/2014      | 2014-07-01 | 2014-11-30    | 11/2014           | 2014-11-01
-- out  07/2015      | 2015-07-01 | 2015-11-30    | 11/2015           | 2015-11-01
-- out  07/2016      | 2016-07-01 | 2016-11-30    | 11/2016           | 2016-11-01
-- out  07/2017      | 2017-07-01 | 2017-11-30    | 11/2017           | 2017-11-01
-- out  07/2018      | 2018-07-01 | 2018-11-30    | 11/2018           | 2018-11-01
-- out  07/2019      | 2019-07-01 | 2019-11-30    | 11/2019           | 2019-11-01
-- out  07/2020      | 2020-07-01 | 2020-07-31    | 07/2020           | 2020-07-02
-- out  12/2013      | 2013-12-01 | 2014-06-30    | 06/2014           | 2014-06-01
-- out  12/2014      | 2014-12-01 | 2015-06-30    | 06/2015           | 2015-06-01
-- out  12/2015      | 2015-12-01 | 2016-06-30    | 06/2016           | 2016-06-01
-- out  12/2016      | 2016-12-01 | 2017-06-30    | 06/2017           | 2017-06-01
-- out  12/2017      | 2017-12-01 | 2018-06-30    | 06/2018           | 2018-06-01
-- out  12/2018      | 2018-12-01 | 2019-06-30    | 06/2019           | 2019-06-01
-- out  12/2019      | 2019-12-01 | 2020-06-30    | 06/2020           | 2020-06-01

于 2020-08-14T13:03:19.663 回答