สร้างวันจากช่วงวันที่


135

ฉันต้องการเรียกใช้แบบสอบถามเช่น

select ... as days where `date` is between '2010-01-20' and '2010-01-24'

และส่งคืนข้อมูลที่ต้องการ:

วัน
----------
2010/01/20
2010/01/21
2010/01/22
2010-01-23
2010/01/24

10
ไม่มีปัญหาอื่น ๆ ที่แนบมากับคำถามนี้ คำถามข้างต้นคือปัญหาการเรียนรู้หลักสูตร SQL
Pentium10

คุณต้องการชุดวันที่ตามช่วงวันที่ที่เลือกหรือไม่
Derek Adair

1
ฉันกำลังคิดถึงการใช้งานเพื่อค้นหาปัญหาให้คุณ ... หากคุณมีงานที่ต้องกรอกข้อมูลในตารางที่ขาดหายไป และคุณต้องเรียกใช้แบบสอบถามในแต่ละวันฉันกำลังคิดอะไรบางอย่างinsert into table select ... as days date between '' and ''
Pentium10

13
ตัวอย่างสำหรับการใช้งานคือการสร้างสถิติและรวมแถวสำหรับวันที่ที่คุณไม่มีข้อมูล หากคุณกำลังจัดกลุ่มบางกลุ่มอาจเร็วกว่ามากในการสร้างข้อมูลทั้งหมดใน SQL และเพิ่มลงในรูปแบบใดก็ได้ที่คุณต้องการแทนที่จะทิ้งข้อมูลของคุณตามที่เป็นในภาษาของคุณแล้วเริ่มวนรอบและเพิ่มของคุณ รถเปล่า
Nanne

1
@Nanne นั่นคือเหตุผลที่ฉันบันทึกคำถามนี้ ฉันต้องการข้อมูลข้างต้นเพื่อ LEFT JOIN เป็นข้อมูลซึ่งอาจไม่มีอยู่ในบางวัน
Josh Diehl

คำตอบ:


318

วิธีนี้ใช้ไม่ห่วงขั้นตอนหรือตารางชั่วคราว แบบสอบถามย่อยสร้างวันที่ในช่วง 10,000 วันที่ผ่านมาและสามารถขยายออกไปข้างหลังหรือไกลที่สุดเท่าที่คุณต้องการ

select a.Date 
from (
    select curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.a) + (1000 * d.a) ) DAY as Date
    from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as d
) a
where a.Date between '2010-01-20' and '2010-01-24' 

เอาท์พุท:

Date
----------
2010-01-24
2010-01-23
2010-01-22
2010-01-21
2010-01-20

หมายเหตุเกี่ยวกับประสิทธิภาพ

ทดสอบที่นี่ประสิทธิภาพที่ดีอย่างน่าประหลาดใจ: แบบสอบถามข้างต้นใช้เวลา 0.0009 วินาที

หากเราขยายข้อความค้นหาย่อยเพื่อสร้างประมาณ 100,000 หมายเลข (และประมาณ 274 ปีที่มีมูลค่าของวันที่) จะทำงานใน 0.0458 วินาที

อนึ่งนี่เป็นเทคนิคแบบพกพาที่ทำงานกับฐานข้อมูลส่วนใหญ่ที่มีการปรับเปลี่ยนเล็กน้อย

ตัวอย่าง SQL Fiddle คืน 1,000 วัน


6
คุณจะเห็นประสิทธิภาพที่ดีขึ้นถ้าคุณเปลี่ยนUNIONไปUNION ALL- ตรวจสอบเวลาของการสูญเสียที่ซ้ำกันจะลบที่ไม่อยู่ มันเป็น IMO ที่ซับซ้อนเกินไป - ถ้าคุณจะสร้างชุดผลลัพธ์โดยใช้ UNION ทำไมไม่เพียงแค่ระบุวันที่และใช้งานมัน
OMG Ponies

7
ทำไมไม่เพียงแค่ระบุวันที่และทำมันด้วย - เพราะวิธีการด้านบนช่วยให้คุณสามารถสร้างชุดของตัวเลข (และวันที่) โดยไม่ต้องมีการสร้างตาราง เห็นได้ชัดว่าเป็นวันที่ 5 นานเกินไป แต่ถึงอย่างนั้นถ้าคุณเข้าร่วมกับตารางที่คุณไม่ทราบวันที่ล่วงหน้า แต่เพียงค่านาทีและค่าสูงสุดที่เป็นไปได้มันก็สมเหตุสมผล
RedFilter

2
มัน "เจ็บปวด" เพียงแค่ใช้ฟังก์ชั่น DATETIME แทนคำสั่ง UNION ที่คุณสร้างขึ้นแล้ว? มันช่วยลดความต้องการตรรกะที่คุณต้องเพิ่มลงได้ ดังนั้น - คุณได้ทำการสืบค้นที่ซับซ้อนมากเกินไป คำสั่ง UNION ไม่สามารถปรับขนาดได้ - ระบุวันที่หรือหมายเลขใครต้องการอัปเดตเพื่อรองรับ 20 หรือ 30 วัน
OMG Ponies

23
เป็นเรื่องที่ดีมากที่ได้เห็นคำตอบของคำถามไม่ใช่ความคิดเห็นที่ไม่รู้จบไม่สามารถทำได้หรือไม่ควรทำ สิ่งส่วนใหญ่สามารถทำได้และ "ควร" มีความหมายเฉพาะในบริบทซึ่งแตกต่างกันสำหรับทุกคน คำตอบนี้ช่วยฉันแม้ว่าฉันจะรู้ตัวดีว่ามีวิธีที่ดีกว่าในสถานการณ์ส่วนใหญ่
โจ

7
พวกคุณที่ไม่สามารถรับแบบสอบถามนี้ให้ทำงานได้: โปรดตบหน้าตัวเองแล้วอ่านความคิดเห็นของ OP เกี่ยวกับแบบสอบถามนี้ที่สร้างวันที่ 1000 ตั้งแต่ปี 2010 เป็นมากกว่า 1,000 วันที่ผ่านมาคุณจะต้องปรับการค้นหาให้สอดคล้อง
Noel Baron

32

นี่คือรูปแบบอื่นโดยใช้มุมมอง:

CREATE VIEW digits AS
  SELECT 0 AS digit UNION ALL
  SELECT 1 UNION ALL
  SELECT 2 UNION ALL
  SELECT 3 UNION ALL
  SELECT 4 UNION ALL
  SELECT 5 UNION ALL
  SELECT 6 UNION ALL
  SELECT 7 UNION ALL
  SELECT 8 UNION ALL
  SELECT 9;

CREATE VIEW numbers AS
  SELECT
    ones.digit + tens.digit * 10 + hundreds.digit * 100 + thousands.digit * 1000 AS number
  FROM
    digits as ones,
    digits as tens,
    digits as hundreds,
    digits as thousands;

CREATE VIEW dates AS
  SELECT
    SUBDATE(CURRENT_DATE(), number) AS date
  FROM
    numbers;

และจากนั้นคุณก็สามารถทำได้ (ดูว่าสง่างามเป็นอย่างไร):

SELECT
  date
FROM
  dates
WHERE
  date BETWEEN '2010-01-20' AND '2010-01-24'
ORDER BY
  date

ปรับปรุง

มันเป็นที่น่าสังเกตว่าคุณจะสามารถที่จะสร้างที่ผ่านมาวันที่เริ่มต้นจากวันที่ปัจจุบัน หากคุณต้องการสร้างช่วงวันที่ใด ๆ (ในอดีตอนาคตและในระหว่าง) คุณจะต้องใช้มุมมองนี้แทน:

CREATE VIEW dates AS
  SELECT
    SUBDATE(CURRENT_DATE(), number) AS date
  FROM
    numbers
  UNION ALL
  SELECT
    ADDDATE(CURRENT_DATE(), number + 1) AS date
  FROM
    numbers;

1
มันไม่ได้ผลในทุกกรณี เลือกวันที่จากวันที่วันที่ระหว่าง '2014-12-01' และ '2014-12-28' เรียงตามวันที่
vasanth

3
ดีโทร @ user927258 นี่เป็นเพราะมุมมองแรกที่datesกล่าวถึงข้างต้นคำนวณวันที่เริ่มต้นจากวันที่ปัจจุบันซึ่งเป็นเหตุผลที่คุณจะไม่สามารถเรียกคืนวันที่ที่ตั้งไว้ในอนาคต คำตอบจาก @RedFilter ทนทุกข์ทรมานจากข้อบกพร่องการออกแบบเดียวกัน ฉันได้เพิ่มวิธีแก้ปัญหาในคำตอบของฉัน
Stéphane

การใช้มุมมองบางอย่างจะทำให้แบบสอบถามง่ายขึ้นและทำให้สามารถนำมาใช้ซ้ำได้ แม้ว่าพวกเขาจะทำสิ่งเดียวกันโดยพื้นฐานแล้วUNIONประโยคทั้งหมดนั้นดูแปลก ๆ ในคำสั่ง SQL เดี่ยว
สจ๊วต

24

คำตอบที่ยอมรับใช้ไม่ได้กับ PostgreSQL (ข้อผิดพลาดทางไวยากรณ์ที่หรือใกล้กับ "a")

วิธีที่คุณทำเช่นนี้ใน PostgreSQL ก็คือการใช้generate_seriesฟังก์ชั่นเช่น:

SELECT day::date
FROM generate_series('2010-01-20', '2010-01-24', INTERVAL '1 day') day;

    day
------------
 2010-01-20
 2010-01-21
 2010-01-22
 2010-01-23
 2010-01-24
(5 rows)

14

การใช้ Common Table Expression (CTE) แบบเรียกซ้ำคุณสามารถสร้างรายการวันที่จากนั้นเลือกจากมัน เห็นได้ชัดว่าโดยปกติคุณไม่ต้องการที่จะสร้างสามล้านเดทดังนั้นนี่ก็แสดงให้เห็นถึงความเป็นไปได้ คุณสามารถ จำกัด ช่วงวันที่ภายใน CTE และละเว้นส่วนคำสั่ง select จากคำสั่ง select โดยใช้ CTE

with [dates] as (
    select convert(datetime, '1753-01-01') as [date] --start
    union all
    select dateadd(day, 1, [date])
    from [dates]
    where [date] < '9999-12-31' --end
)
select [date]
from [dates]
where [date] between '2013-01-01' and '2013-12-31'
option (maxrecursion 0)

บน Microsoft SQL Server 2005 การสร้างรายการ CTE ของวันที่ที่เป็นไปได้ทั้งหมดนั้นใช้เวลา 1:08 การสร้างหนึ่งร้อยปีนั้นใช้เวลาน้อยกว่าหนึ่งวินาที


7

แบบสอบถาม MSSQL

select datetable.Date 
from (
    select DATEADD(day,-(a.a + (10 * b.a) + (100 * c.a)),getdate()) AS Date
    from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4
     union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a

    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4
     union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b

    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4
     union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
) datetable
where datetable.Date between '2014-01-20' and '2014-01-24' 
order by datetable.Date DESC

เอาท์พุต

Date
-----
2014-01-23 12:35:25.250
2014-01-22 12:35:25.250
2014-01-21 12:35:25.250
2014-01-20 12:35:25.250

2
ถ้าฉันเลื่อนลงไปอีกหน่อย ... ถอนหายใจ ยังไงก็ตามขอบคุณ ฉันเพิ่มนักแสดง (<expression> เป็นวันที่) เพื่อลบเวลาในเวอร์ชันของฉัน นอกจากนี้ยังใช้ในกรณีที่ a.Date ระหว่าง GETDATE () - 365 และ GETDATE () ... หากคุณเรียกใช้คิวรีของคุณวันนี้มันจะไม่ให้แถวถ้าคุณไม่สังเกตเห็นวันที่ในตำแหน่ง = P
Ricardo C

4

โซลูชันโรงเรียนเก่าสำหรับการทำเช่นนี้โดยไม่มีลูป / เคอร์เซอร์คือการสร้างNUMBERSตารางซึ่งมีคอลัมน์จำนวนเต็มเดียวที่มีค่าเริ่มต้นที่ 1

CREATE TABLE  `example`.`numbers` (
  `id` int(10) unsigned NOT NULL auto_increment,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

คุณต้องเติมข้อมูลในตารางให้เพียงพอเพื่อครอบคลุมความต้องการของคุณ:

INSERT INTO NUMBERS (id) VALUES (NULL);

เมื่อคุณมีNUMBERSตารางคุณสามารถใช้:

SELECT x.start_date + INTERVAL n.id-1 DAY
  FROM NUMBERS n
  JOIN (SELECT STR_TO_DATE('2010-01-20', '%Y-%m-%d') AS start_date 
          FROM DUAL) x
 WHERE x.start_date + INTERVAL n.id-1 DAY <= '2010-01-24'

โซลูชันที่ใช้เทคโนโลยีขั้นต่ำคือ:

SELECT STR_TO_DATE('2010-01-20', '%Y-%m-%d')
 FROM DUAL
UNION ALL
SELECT STR_TO_DATE('2010-01-21', '%Y-%m-%d')
 FROM DUAL
UNION ALL
SELECT STR_TO_DATE('2010-01-22', '%Y-%m-%d')
 FROM DUAL
UNION ALL
SELECT STR_TO_DATE('2010-01-23', '%Y-%m-%d')
 FROM DUAL
UNION ALL
SELECT STR_TO_DATE('2010-01-24', '%Y-%m-%d')
 FROM DUAL

คุณจะใช้มันเพื่ออะไร


เพื่อสร้างรายการของวันที่หรือตัวเลขเพื่อที่จะเข้าร่วมซ้ายเพื่อ คุณจะทำสิ่งนี้เพื่อดูว่ามีช่องว่างในข้อมูลอยู่ที่ใดเนื่องจากคุณอยู่ซ้ายเข้าสู่รายการข้อมูลต่อเนื่อง - ค่า Null จะทำให้เห็นได้ชัดเมื่อมีช่องว่าง


1
DUALตารางการสนับสนุนโดย Oracle และ MySQL เพื่อใช้เป็นขาตั้งในตารางในFROMข้อ ไม่มีอยู่การเลือกค่าจากนั้นจะคืนค่าใด ๆ แนวคิดคือต้องมีสแตนอินเนื่องจากคิวรี SELECT ต้องใช้FROMประโยคที่ระบุอย่างน้อยหนึ่งตาราง
OMG Ponies

1
+1 สำหรับการสร้างตารางตัวเลขถาวรแทนที่จะทำให้ RDBMS สร้างขึ้นด้วยทุกครั้งที่คุณต้องการแบบสอบถาม ตารางเสริมไม่ใช่คนเลว!
เบคอน Bits

4

สำหรับ Access 2010 - จำเป็นต้องมีหลายขั้นตอน ฉันทำตามรูปแบบเดียวกันกับที่โพสต์ไว้ด้านบน แต่คิดว่าฉันสามารถช่วยคนใน Access ได้ ใช้งานได้ดีสำหรับฉันฉันไม่จำเป็นต้องเก็บตารางวันที่เพาะไว้

สร้างตารางที่เรียกว่า DUAL (คล้ายกับการทำงานของตาราง Oracle DUAL)

  • ID (ตัวเลขอัตโนมัติ)
  • DummyColumn (ข้อความ)
  • เพิ่มหนึ่งแถวค่า (1, "DummyRow")

สร้างแบบสอบถามที่ชื่อว่า "ZeroThru9Q"; ป้อนไวยากรณ์ต่อไปนี้ด้วยตนเอง:

SELECT 0 AS a
FROM dual
UNION ALL
SELECT 1
FROM dual
UNION ALL
SELECT 2
FROM dual
UNION ALL
SELECT 3
FROM dual
UNION ALL
SELECT 4
FROM dual
UNION ALL
SELECT 5
FROM dual
UNION ALL
SELECT 6
FROM dual
UNION ALL
SELECT 7
FROM dual
UNION ALL
SELECT 8
FROM dual
UNION ALL
SELECT 9
FROM dual;

สร้างแบบสอบถามที่ชื่อว่า "TodayMinus1KQ" (สำหรับวันที่ก่อนวันนี้); ป้อนไวยากรณ์ต่อไปนี้ด้วยตนเอง:

SELECT date() - (a.a + (10 * b.a) + (100 * c.a)) AS MyDate
FROM
  (SELECT *
   FROM ZeroThru9Q) AS a,

  (SELECT *
   FROM ZeroThru9Q) AS b,

  (SELECT *
   FROM ZeroThru9Q) AS c

สร้างแบบสอบถามที่ชื่อว่า "TodayPlus1KQ" (สำหรับวันที่หลังจากวันนี้); ป้อนไวยากรณ์ต่อไปนี้ด้วยตนเอง:

SELECT date() + (a.a + (10 * b.a) + (100 * c.a)) AS MyDate
FROM
  (SELECT *
   FROM ZeroThru9Q) AS a,

  (SELECT *
   FROM ZeroThru9Q) AS b,

  (SELECT *
   FROM ZeroThru9Q) AS c;

สร้างแบบสอบถามแบบร่วมชื่อ "TodayPlusMinus1KQ" (สำหรับวันที่ +/- 1,000 วัน):

SELECT MyDate
FROM TodayMinus1KQ
UNION
SELECT MyDate
FROM TodayPlus1KQ;

ตอนนี้คุณสามารถใช้แบบสอบถาม:

SELECT MyDate
FROM TodayPlusMinus1KQ
WHERE MyDate BETWEEN #05/01/2014# and #05/30/2014#

3

ขั้นตอน + ตารางชั่วคราว:

DELIMITER $$

CREATE DEFINER=`root`@`localhost` PROCEDURE `days`(IN dateStart DATE, IN dateEnd DATE)
BEGIN

    CREATE TEMPORARY TABLE IF NOT EXISTS date_range (day DATE);

    WHILE dateStart <= dateEnd DO
      INSERT INTO date_range VALUES (dateStart);
      SET dateStart = DATE_ADD(dateStart, INTERVAL 1 DAY);
    END WHILE;

    SELECT * FROM date_range;
    DROP TEMPORARY TABLE IF EXISTS date_range;

END

3

ขอบคุณ Pentium10 - คุณทำให้ฉันเข้าร่วม stackoverflow :) - นี่คือพอร์ตของฉันไปยัง msaccess - คิดว่ามันจะใช้ได้กับทุกรุ่น:

SELECT date_value
FROM (SELECT a.espr1+(10*b.espr1)+(100*c.espr1) AS integer_value,
dateadd("d",integer_value,dateserial([start_year], [start_month], [start_day])) as date_value
FROM (select * from 
    (
    select top 1 "0" as espr1 from MSysObjects
    union all
    select top 1 "1" as espr2 from MSysObjects
    union all
    select top 1 "2" as espr3 from MSysObjects
    union all
    select top 1 "3" as espr4 from MSysObjects
    union all
    select top 1 "4" as espr5 from MSysObjects
    union all
    select top 1 "5" as espr6 from MSysObjects
    union all
    select top 1 "6" as espr7 from MSysObjects
    union all
    select top 1 "7" as espr8 from MSysObjects
    union all
    select top 1 "8" as espr9 from MSysObjects
    union all
    select top 1 "9" as espr9 from MSysObjects
    ) as a,
    (
    select top 1 "0" as espr1 from MSysObjects
    union all
    select top 1 "1" as espr2 from MSysObjects
    union all
    select top 1 "2" as espr3 from MSysObjects
    union all
    select top 1 "3" as espr4 from MSysObjects
    union all
    select top 1 "4" as espr5 from MSysObjects
    union all
    select top 1 "5" as espr6 from MSysObjects
    union all
    select top 1 "6" as espr7 from MSysObjects
    union all
    select top 1 "7" as espr8 from MSysObjects
    union all
    select top 1 "8" as espr9 from MSysObjects
    union all
    select top 1 "9" as espr9 from MSysObjects
    ) as b,
    (
    select top 1 "0" as espr1 from MSysObjects
    union all
    select top 1 "1" as espr2 from MSysObjects
    union all
    select top 1 "2" as espr3 from MSysObjects
    union all
    select top 1 "3" as espr4 from MSysObjects
    union all
    select top 1 "4" as espr5 from MSysObjects
    union all
    select top 1 "5" as espr6 from MSysObjects
    union all
    select top 1 "6" as espr7 from MSysObjects
    union all
    select top 1 "7" as espr8 from MSysObjects
    union all
    select top 1 "8" as espr9 from MSysObjects
    union all
    select top 1 "9" as espr9 from MSysObjects
    ) as c   
)  as d) 
WHERE date_value 
between dateserial([start_year], [start_month], [start_day]) 
and dateserial([end_year], [end_month], [end_day]);

MSysObjects ที่อ้างถึงเพียง 'ทำให้การเข้าถึงจำเป็นต้องมีการนับตาราง' อย่างน้อย 1 เร็กคอร์ดในจากส่วนคำสั่ง - ตารางใด ๆ ที่มีอย่างน้อย 1 เร็กคอร์ดจะทำ


2

ตามที่ระบุไว้ (หรืออย่างน้อยพูดพาดพิงถึง) ในคำตอบที่ยอดเยี่ยมจำนวนมากที่ได้รับแล้วปัญหานี้จะแก้ไขได้อย่างง่ายดายเมื่อคุณมีชุดของตัวเลขที่จะทำงานกับ

หมายเหตุ:ต่อไปนี้คือ T-SQL แต่เป็นเพียงการนำแนวคิดทั่วไปของฉันไปใช้ที่นี่และบนอินเทอร์เน็ตเป็นจำนวนมาก มันควรจะง่ายในการแปลงรหัสเป็นภาษาที่คุณเลือก

อย่างไร? พิจารณาคำถามนี้:

SELECT DATEADD(d, N, '0001-01-22')
FROM Numbers -- A table containing the numbers 0 through N
WHERE N <= 5;

ด้านบนสร้างช่วงวันที่ 1/22/0001 - 1/27/0001 และไม่สำคัญมาก มี 2 ชิ้นสำคัญของข้อมูลในแบบสอบถามดังกล่าวข้างต้นคือ: วันที่เริ่มต้นของ0001-01-22และชดเชย5ของ หากเรารวมข้อมูลสองชิ้นนี้เข้าด้วยกันเราก็จะมีวันที่สิ้นสุด ดังนั้นเมื่อได้รับสองวันการสร้างช่วงสามารถแบ่งได้ดังนี้:

  • ค้นหาความแตกต่างระหว่างสองวันที่กำหนด (ชดเชย) ง่าย:

    -- Returns 125 SELECT ABS(DATEDIFF(d, '2014-08-22', '2014-12-25'))

    ใช้ABS()ที่นี่เพื่อให้แน่ใจว่าคำสั่งวันที่ไม่เกี่ยวข้อง

  • สร้างชุดตัวเลขที่ จำกัด และทำได้ง่าย:

    -- Returns the numbers 0-2 SELECT N = ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) - 1 FROM(SELECT 'A' AS S UNION ALL SELECT 'A' UNION ALL SELECT 'A')

    สังเกตว่าเราไม่สนใจสิ่งที่เราเลือกFROMที่นี่ เราแค่ต้องตั้งค่าให้ทำงานด้วยเพื่อที่เราจะนับจำนวนแถวในนั้น ส่วนตัวผมใช้ TVF บางคนใช้ CTE ส่วนคนอื่นใช้ตารางตัวเลขแทนคุณจะได้ความคิด ฉันแนะนำให้ใช้วิธีที่มีประสิทธิภาพที่สุดที่คุณเข้าใจ

การรวมสองวิธีเหล่านี้จะช่วยแก้ปัญหาของเรา:

DECLARE @date1 DATE = '9001-11-21';
DECLARE @date2 DATE = '9001-11-23';

SELECT D = DATEADD(d, N, @date1)
FROM (
    SELECT N = ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) - 1
    FROM (SELECT 'A' AS S UNION ALL SELECT 'A' UNION ALL SELECT 'A') S
) Numbers
WHERE N <= ABS(DATEDIFF(d, @date1, @date2));

ตัวอย่างข้างต้นเป็นรหัสที่น่ากลัว แต่แสดงให้เห็นว่าทุกอย่างมารวมกันได้อย่างไร

สนุกมาก

ฉันต้องทำสิ่งนี้มากดังนั้นฉันจึงสรุปเหตุผลเป็นสอง TVF ตัวแรกสร้างช่วงของตัวเลขและตัวที่สองใช้ฟังก์ชันนี้เพื่อสร้างช่วงของวันที่ GenerateRangeSmallIntคณิตศาสตร์คือเพื่อให้แน่ใจเพื่อป้อนข้อมูลที่ไม่สำคัญและเพราะผมต้องการที่จะใช้อย่างเต็มรูปแบบของตัวเลขในใช้ได้

ฟังก์ชั่นต่อไปนี้ใช้เวลาประมาณ 16ms ของเวลา CPU เพื่อส่งคืนช่วงสูงสุดวันที่ 65536

CREATE FUNCTION dbo.GenerateRangeDate (   
    @date1 DATE,   
    @date2 DATE   
)   
RETURNS TABLE
WITH SCHEMABINDING   
AS   
RETURN (
    SELECT D = DATEADD(d, N + 32768, CASE WHEN @date1 <= @date2 THEN @date1 ELSE @date2 END)
    FROM dbo.GenerateRangeSmallInt(-32768, ABS(DATEDIFF(d, @date1, @date2)) - 32768)
);

GO

CREATE FUNCTION dbo.GenerateRangeSmallInt (
    @num1 SMALLINT = -32768
  , @num2 SMALLINT = 32767
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN (
    WITH Numbers(N) AS (
        SELECT N FROM(VALUES
            (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 16
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 32
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 48
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 64
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 80
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 96
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 112
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 128
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 144
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 160
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 176
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 192
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 208
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 224
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 240
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 256
        ) V (N)
    )
    SELECT TOP(ABS(CAST(@num1 AS INT) - CAST(@num2 AS INT)) + 1)
           N = ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) + CASE WHEN @num1 <= @num2 THEN @num1 ELSE @num2 END - 1
    FROM Numbers A
       , Numbers B
);

2

ลองนี้

SELECT TO_DATE('20160210','yyyymmdd') - 1 + LEVEL AS start_day 
from DUAL
connect by level <= (TO_DATE('20160228','yyyymmdd') + 1) - TO_DATE('20160210','yyyymmdd') ;

2

คุณต้องการรับช่วงวันที่

ในตัวอย่างของคุณคุณต้องการรับวันที่ระหว่าง '2010-01-20' และ '2010-01-24'

ทางออกที่เป็นไปได้:

 select date_add('2010-01-20', interval row day) from
 ( 
    SELECT @row := @row + 1 as row FROM 
    (select 0 union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t,
    (select 0 union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t2, 
    (select 0 union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t3, 
    (select 0 union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t4, 
    (SELECT @row:=-1) r
 ) sequence
 where date_add('2010-01-20', interval row day) <= '2010-01-24'

คำอธิบาย

MySQL มีฟังก์ชันdate_addดังนั้น

select date_add('2010-01-20', interval 1 day)

จะให้คุณ

2010-01-21

DateDiffฟังก์ชั่นจะช่วยให้คุณรู้ว่าคุณมักจะต้องทำซ้ำนี้

select datediff('2010-01-24', '2010-01-20')

ซึ่งผลตอบแทน

 4

การรับรายการวันที่ในช่วงวันที่นั้นลดลงเพื่อสร้างลำดับเลขจำนวนเต็มดูสร้างลำดับจำนวนเต็มใน MySQL

คำตอบที่ได้รับการโหวตมากที่สุดที่นี่ได้ใช้วิธีการที่คล้ายกันกับhttps://stackoverflow.com/a/2652051/1497139เป็นพื้นฐาน:

SELECT @row := @row + 1 as row FROM 
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t,
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t2, 
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t3, 
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t4, 
(SELECT @row:=0) r
limit 4

ซึ่งจะส่งผลให้

row
1.0
2.0
3.0
4.0

ตอนนี้แถวสามารถใช้เพื่อสร้างรายการวันที่จากวันที่เริ่มต้นที่กำหนด ในการรวมวันที่เริ่มต้นเราเริ่มต้นด้วยแถว -1;

select date_add('2010-01-20', interval row day) from
 ( 
    SELECT @row := @row + 1 as row FROM 
    (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t,
    (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t2, 
    (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t3, 
    (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t4, 
    (SELECT @row:=-1) r
 ) sequence
 where date_add('2010-01-20', interval row day) <= '2010-01-24'

1

ถ้าคุณต้องการมากกว่านั้นสองสามวันคุณต้องมีโต๊ะ

สร้างช่วงวันที่ใน mysql

แล้ว

select from days.day, count(mytable.field) as fields from days left join mytable on day=date where date between x and y;

3
เหตุใดคุณจึงโพสต์สิ่งนี้เนื่องจากคำตอบข้างต้นไม่จำเป็นต้องมีตารางและให้การแก้ปัญหา?
Pentium10

1

สร้างวันที่ระหว่างสองฟิลด์วันที่

หากคุณทราบเกี่ยวกับแบบสอบถาม SQL CTE โซลูชันนี้จะช่วยคุณแก้ไขคำถามของคุณ

นี่คือตัวอย่าง

เรามีวันที่ในหนึ่งตาราง

ชื่อตาราง:“ testdate”

STARTDATE   ENDDATE
10/24/2012  10/24/2012
10/27/2012  10/29/2012
10/30/2012  10/30/2012

ต้องการผลลัพธ์:

STARTDATE
10/24/2012
10/27/2012
10/28/2012
10/29/2012
10/30/2012

สารละลาย:

WITH CTE AS
  (SELECT DISTINCT convert(varchar(10),StartTime, 101) AS StartTime,
                   datediff(dd,StartTime, endTime) AS diff
   FROM dbo.testdate
   UNION ALL SELECT StartTime,
                    diff - 1 AS diff
   FROM CTE
   WHERE diff<> 0)
SELECT DISTINCT DateAdd(dd,diff, StartTime) AS StartTime
FROM CTE

คำอธิบาย: คำอธิบายแบบสอบถามแบบเรียกซ้ำ CTE

  • ส่วนแรกของเคียวรี:

    SELECT DISTINCT convert(varchar(10), StartTime, 101) AS StartTime, datediff(dd, StartTime, endTime) AS diff FROM dbo.testdate

    คำอธิบาย: firstcolumn คือ“ startdate” คอลัมน์ที่สองคือความแตกต่างของวันที่เริ่มต้นและวันที่สิ้นสุดในวันและจะถือว่าเป็นคอลัมน์“ diff”

  • ส่วนที่สองของแบบสอบถาม:

    UNION ALL SELECT StartTime, diff-1 AS diff FROM CTE WHERE diff<>0

    คำอธิบาย: สหภาพทั้งหมดจะสืบทอดผลลัพธ์ของแบบสอบถามข้างต้นจนกว่าผลลัพธ์จะเป็นโมฆะดังนั้นผลลัพธ์“ StartTime” จึงสืบทอดมาจากคิวรี CTE ที่สร้างขึ้นและจาก diff ลดลง - 1 ดังนั้นจึงดูเหมือนว่า 3, 2 และ 1 จนถึง 0

ตัวอย่างเช่น

STARTDATE   DIFF
10/24/2012  0
10/27/2012  0
10/27/2012  1
10/27/2012  2
10/30/2012  0

ข้อกำหนดผลลัพธ์

STARTDATE       Specification
10/24/2012  --> From Record 1
10/27/2012  --> From Record 2
10/27/2012  --> From Record 2
10/27/2012  --> From Record 2
10/30/2012  --> From Record 3
  • ส่วนที่ 3 ของการค้นหา

    SELECT DISTINCT DateAdd(dd,diff, StartTime) AS StartTime FROM CTE

    มันจะเพิ่มวัน“ diff” ใน“ startdate” ดังนั้นผลลัพธ์ควรเป็นดังนี้

ผลลัพธ์

STARTDATE
10/24/2012
10/27/2012
10/28/2012
10/29/2012
10/30/2012

1

สั้นกว่าคำตอบที่ยอมรับแนวคิดเดียวกัน:

(SELECT TRIM('2016-01-05' + INTERVAL a + b DAY) date
FROM
(SELECT 0 a UNION SELECT 1 a UNION SELECT 2 UNION SELECT 3
UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7
UNION SELECT 8 UNION SELECT 9 ) d,
(SELECT 0 b UNION SELECT 10 UNION SELECT 20
UNION SELECT 30 UNION SELECT 40) m
WHERE '2016-01-05' + INTERVAL a + b DAY  <=  '2016-01-21')

1

สำหรับทุกคนที่ต้องการสิ่งนี้เป็นมุมมองที่บันทึกไว้ (MySQL ไม่รองรับคำสั่งที่ซ้อนกันในมุมมอง):

create view zero_to_nine as
    select 0 as n union all 
    select 1 union all 
    select 2 union all 
    select 3 union all 
    select 4 union all 
    select 5 union all 
    select 6 union all 
    select 7 union all 
    select 8 union all 
    select 9;

create view date_range as
    select curdate() - INTERVAL (a.n + (10 * b.n) + (100 * c.n)) DAY as date
    from zero_to_nine as a
    cross join zero_to_nine as b
    cross join zero_to_nine as c;

จากนั้นคุณสามารถทำได้

select * from date_range

เพื่อรับ

date
---
2017-06-06
2017-06-05
2017-06-04
2017-06-03
2017-06-02
...

1

ทางออกที่สวยงามโดยใช้ฟังก์ชันการทำงานแบบเรียกซ้ำ (Common Table Expressions) ใหม่ใน MariaDB> = 10.3 และ MySQL> = 8.0

WITH RECURSIVE t as (
    select '2019-01-01' as dt
  UNION
    SELECT DATE_ADD(t.dt, INTERVAL 1 DAY) FROM t WHERE DATE_ADD(t.dt, INTERVAL 1 DAY) <= '2019-04-30'
)
select * FROM t;

ด้านบนส่งคืนตารางวันที่ระหว่าง '2019-01-01' และ '2019-04-30' มันยังเร็วพอสมควร การย้อนเวลากลับไป 1,000 ปี (~ 365,000 วัน) ใช้เวลาประมาณ 400ms ในเครื่องของฉัน


1

เป็นความคิดที่ดีที่จะสร้างวันที่เหล่านี้ได้ทันที อย่างไรก็ตามฉันไม่รู้สึกสบายใจที่จะทำสิ่งนี้ด้วยช่วงที่ค่อนข้างใหญ่ดังนั้นฉันจึงได้วิธีต่อไปนี้:

  1. สร้างตาราง "DatesNumbers" ที่จะเก็บตัวเลขที่ใช้สำหรับการคำนวณวันที่:
CREATE TABLE DatesNumbers (
    i MEDIUMINT NOT NULL,
    PRIMARY KEY (i)
)
COMMENT='Used by Dates view'
;
  1. เติมตารางโดยใช้เทคนิคด้านบนด้วยตัวเลขตั้งแต่ -59999 ถึง 40000 ช่วงนี้จะให้วันที่ฉันจาก 59999 วัน (~ 164 ปี) ด้านหลังถึง 40000 วัน (109 ปี) ล่วงหน้า:
INSERT INTO DatesNumbers
SELECT 
    a.i + (10 * b.i) + (100 * c.i) + (1000 * d.i) + (10000 * e.i) - 59999 AS i
FROM 
  (SELECT 0 AS i UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS a,
  (SELECT 0 AS i UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS b,
  (SELECT 0 AS i UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS c,
  (SELECT 0 AS i UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS d,
  (SELECT 0 AS i UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS e
;
  1. สร้างมุมมอง "วันที่":
SELECT
      i,
      CURRENT_DATE() + INTERVAL i DAY AS Date
FROM
    DatesNumbers

แค่นั้นแหละ.

  • (+) ข้อความค้นหาที่อ่านง่าย
  • (+) ไม่มีในรุ่นที่บินหมายเลข
  • (+) ให้วันที่ในอดีตและในอนาคตและไม่มีสหภาพในมุมมองสำหรับสิ่งนี้เช่นเดียวกับในโพสต์นี้นี้
  • (+) วันที่ "ในอดีตเท่านั้น" หรือ "ในอนาคตเท่านั้น" สามารถถูกกรองโดยใช้WHERE i < 0หรือWHERE i > 0 (PK)
  • (-) ใช้มุมมอง 'ชั่วคราว'

0

เอาล่ะ .. ลองนี่สิ: http://www.devshed.com/c/a/MySQL/Delving-Deeper-into-MySQL-50/
http://dev.mysql.com/doc/refman/5.0/en/ loop-statement.html
http://www.roseindia.net/sql/mysql-example/mysql-loop.shtml

ใช้สิ่งนั้นเพื่อพูดสร้างตารางชั่วคราวแล้วเลือก * บนตารางชั่วคราว หรือแสดงผลลัพธ์ทีละรายการ
สิ่งที่คุณพูดว่าคุณต้องการที่จะทำไม่สามารถทำได้ด้วยคำสั่ง SELECTแต่มันอาจจะเป็นไปได้กับสิ่งที่เฉพาะเจาะจงกับ MySQL
จากนั้นอีกครั้งคุณอาจต้องการเคอร์เซอร์: http://dev.mysql.com/doc/refman/5.0/en/cursors.html


0

สำหรับ Oracle โซลูชันของฉันคือ:

select trunc(sysdate-dayincrement, 'DD') 
  from dual, (select level as dayincrement 
                from dual connect by level <= 30)

Sysdate สามารถเปลี่ยนเป็นวันที่ที่ระบุและจำนวนระดับสามารถเปลี่ยนแปลงได้เพื่อให้วันที่มากขึ้น


0

หากคุณต้องการรายการวันที่ระหว่างสองวัน:

create table #dates ([date] smalldatetime)
while @since < @to
begin
     insert into #dates(dateadd(day,1,@since))
     set @since = dateadd(day,1,@since)
end
select [date] from #dates

* ซอที่นี่: http://sqlfiddle.com/#!6/9eecb/3469


0
set language  'SPANISH'
DECLARE @table table(fechaDesde datetime , fechaHasta datetime ) 
INSERT @table VALUES('20151231' , '20161231');
WITH x AS 
    (
        SELECT   DATEADD( m , 1 ,fechaDesde ) as fecha  FROM @table
        UNION ALL
        SELECT  DATEADD( m , 1 ,fecha )
        FROM @table t INNER JOIN x ON  DATEADD( m , 1 ,x.fecha ) <= t.fechaHasta
    )
SELECT LEFT( CONVERT( VARCHAR, fecha , 112 ) , 6 ) as Periodo_Id 
,DATEPART ( dd, DATEADD(dd,-(DAY(fecha)-1),fecha)) Num_Dia_Inicio
,DATEADD(dd,-(DAY(fecha)-1),fecha) Fecha_Inicio
,DATEPART ( mm , fecha ) Mes_Id
,DATEPART ( yy , fecha ) Anio
,DATEPART ( dd, DATEADD(dd,-(DAY(DATEADD(mm,1,fecha))),DATEADD(mm,1,fecha))) Num_Dia_Fin
,DATEADD(dd,-(DAY(DATEADD(mm,1,fecha))),DATEADD(mm,1,fecha)) ultimoDia
,datename(MONTH, fecha) mes
,'Q' + convert(varchar(10),  DATEPART(QUARTER, fecha)) Trimestre_Name
FROM x 
OPTION(MAXRECURSION 0)

0
DELIMITER $$
CREATE PROCEDURE GenerateRangeDates(IN dateStart DATE, IN dateEnd DATE)
BEGIN

    CREATE TEMPORARY TABLE IF NOT EXISTS dates (day DATE);

    loopDate: LOOP
        INSERT INTO dates(day) VALUES (dateStart); 
        SET dateStart = DATE_ADD(dateStart, INTERVAL 1 DAY);

        IF dateStart <= dateEnd 
            THEN ITERATE loopDate;
            ELSE LEAVE loopDate;
        END IF;
    END LOOP loopDate;

    SELECT day FROM dates;
    DROP TEMPORARY TABLE IF EXISTS dates;

END 
$$

-- Call procedure
call GenerateRangeDates( 
        now() - INTERVAL 40 DAY,
        now()
    );

0

โซลูชันระดับบนสุดของ RedFilters SQLite

select d.Date
from (
    select 
    date(julianday('2010-01-20') + (a.a + (10 * b.a) + (100 * c.a))) as Date
    from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
) d
where 
d.Date between '2010-01-20' and '2010-01-24' 
order by d.Date

0

ปรับปรุงด้วยวันธรรมดาและตารางวันหยุดที่กำหนดเอง microsoft MSSQL 2012 สำหรับตารางวันที่ของ powerpivot https://gist.github.com/josy1024/cb1487d66d9e0ccbd420bc4a23b6e90e

with [dates] as (
    select convert(datetime, '2016-01-01') as [date] --start
    union all
    select dateadd(day, 1, [date])
    from [dates]
    where [date] < '2018-01-01' --end
)
select [date]
, DATEPART (dw,[date]) as Wochentag
, (select holidayname from holidaytable 
where holidaytable.hdate = [date]) 
as Feiertag
from [dates]
where [date] between '2016-01-01' and '2016-31-12'
option (maxrecursion 0)

0
WITH
  Digits AS (SELECT 0 D UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9),
  Dates AS (SELECT adddate('1970-01-01',t4.d*10000 + t3.d*1000 + t2.d*100 + t1.d*10 +t0.d) AS date FROM Digits AS t0, Digits AS t1, Digits AS t2, Digits AS t3, Digits AS t4)
SELECT * FROM Dates WHERE date BETWEEN '2017-01-01' AND '2017-12-31'

0

สามารถสร้างโพรซีเดอร์เพื่อสร้างตารางปฏิทินที่มี timestmap ที่แตกต่างจากวัน ถ้าคุณต้องการตารางสำหรับแต่ละไตรมาส

เช่น

2019-01-22 08:45:00
2019-01-22 09:00:00
2019-01-22 09:15:00
2019-01-22 09:30:00
2019-01-22 09:45:00
2019-01-22 10:00:00

คุณสามารถใช้ได้

CREATE DEFINER=`root`@`localhost` PROCEDURE `generate_calendar_table`()
BEGIN

select unix_timestamp('2014-01-01 00:00:00') into @startts;
select unix_timestamp('2025-01-01 00:00:00') into @endts;

if ( @startts < @endts ) then

    DROP TEMPORARY TABLE IF EXISTS calendar_table_tmp;

    CREATE TEMPORARY TABLE calendar_table_tmp (ts int, dt datetime); 

    WHILE ( @startts < @endts)
        DO 
        SET @startts = @startts + 900;
        INSERT calendar_table_tmp VALUES (@startts, from_unixtime(@startts));
    END WHILE;

END if;

END

แล้วจัดการผ่าน

select ts, dt from calendar_table_tmp;

ที่ให้คุณยัง ts

'1548143100', '2019-01-22 08:45:00'
'1548144000', '2019-01-22 09:00:00'
'1548144900', '2019-01-22 09:15:00'
'1548145800', '2019-01-22 09:30:00'
'1548146700', '2019-01-22 09:45:00'
'1548147600', '2019-01-22 10:00:00'

จากที่นี่คุณสามารถเริ่มเพิ่มข้อมูลอื่น ๆ เช่น

select ts, dt, weekday(dt) as wd from calendar_table_tmp;

หรือสร้างตารางจริงด้วยคำสั่งสร้างตาราง


0

คำตอบทั่วไปเพิ่มเติมที่ทำงานใน AWS MySQL

select datetable.Date
from (
    select date_format(adddate(now(),-(a.a + (10 * b.a) + (100 * c.a))),'%Y-%m-%d') AS Date
    from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4
     union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a

    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4
     union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b

    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4
     union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
) datetable
where datetable.Date between now() - INTERVAL 14 Day and Now()
order by datetable.Date DESC

-1

อีกหนึ่งโซลูชั่นสำหรับ mysql 8.0.1 และ mariadb 10.2.2 โดยใช้นิพจน์ทั่วไปแบบเรียกซ้ำ:

with recursive dates as (
    select '2010-01-20' as date
    union all
    select date + interval 1 day from dates where date < '2010-01-24'
)
select * from dates;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.