Saya ingin menjalankan kueri seperti
select ... as days where `date` is between '2010-01-20' and '2010-01-24'
Dan kembalikan data seperti:
hari ---------- 2010-01-20 2010-01-21 2010-01-22 2010-01-23 2010-01-24
Saya ingin menjalankan kueri seperti
select ... as days where `date` is between '2010-01-20' and '2010-01-24'
Dan kembalikan data seperti:
hari ---------- 2010-01-20 2010-01-21 2010-01-22 2010-01-23 2010-01-24
insert into table select ... as days date between '' and ''
Jawaban:
Solusi ini tidak menggunakan loop, prosedur, atau tabel temp . Subkueri menghasilkan tanggal untuk 10.000 hari terakhir, dan dapat diperpanjang sejauh yang Anda inginkan.
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'
Keluaran:
Date
----------
2010-01-24
2010-01-23
2010-01-22
2010-01-21
2010-01-20
Catatan tentang Kinerja
Pengujian itu di sini , kinerja yang mengejutkan baik: query di atas membutuhkan 0,0009 detik.
Jika kita memperluas subquery untuk menghasilkan kira-kira. 100.000 angka (dan dengan demikian tanggal sekitar 274 tahun), itu berjalan dalam 0,0458 detik.
Kebetulan, ini adalah teknik yang sangat portabel yang bekerja dengan sebagian besar database dengan sedikit penyesuaian.
UNION
ke UNION ALL
- membuang-buang waktu memeriksa duplikat untuk dihapus yang tidak ada. Ini IMO yang terlalu rumit - jika Anda akan membuat kumpulan hasil menggunakan UNION, mengapa tidak menentukan tanggal dan selesai dengannya?
Berikut variasi lain menggunakan tampilan:
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;
Dan kemudian Anda dapat melakukannya (lihat betapa elegannya itu?):
SELECT
date
FROM
dates
WHERE
date BETWEEN '2010-01-20' AND '2010-01-24'
ORDER BY
date
Memperbarui
Perlu dicatat bahwa Anda hanya dapat menghasilkan tanggal yang sudah lewat mulai dari tanggal sekarang . Jika Anda ingin membuat segala jenis rentang tanggal (lampau, mendatang, dan di antaranya), Anda harus menggunakan tampilan ini sebagai gantinya:
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;
dates
disebutkan di atas menghitung tanggal mulai dari tanggal saat ini, itulah sebabnya Anda tidak dapat mengambil tanggal yang ditetapkan di masa mendatang. Jawaban dari @RedFilter menderita cacat desain yang sama. Saya telah menambahkan solusi dalam jawaban saya.
UNION
klausa tersebut terlihat aneh dalam satu pernyataan SQL.
Jawaban yang diterima tidak berfungsi untuk PostgreSQL (kesalahan sintaks di atau dekat "a").
Cara Anda melakukan ini di PostgreSQL adalah dengan menggunakan generate_series
fungsi, yaitu:
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)
Dengan menggunakan Common Table Expression (CTE) rekursif, Anda dapat membuat daftar tanggal, lalu memilihnya. Jelas Anda biasanya tidak ingin membuat tiga juta tanggal, jadi ini hanya menggambarkan kemungkinannya. Anda dapat dengan mudah membatasi rentang tanggal di dalam CTE dan menghilangkan klausa where dari pernyataan pemilihan menggunakan 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)
Di Microsoft SQL Server 2005, membuat daftar CTE dari semua kemungkinan tanggal membutuhkan waktu 1:08. Menghasilkan seratus tahun membutuhkan waktu kurang dari satu detik.
Kueri 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
Keluaran
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
Solusi jadul untuk melakukan ini tanpa perulangan / kursor adalah dengan membuat NUMBERS
tabel, yang memiliki kolom Bilangan bulat tunggal dengan nilai mulai dari 1.
CREATE TABLE `example`.`numbers` (
`id` int(10) unsigned NOT NULL auto_increment,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Anda perlu mengisi tabel dengan catatan yang cukup untuk memenuhi kebutuhan Anda:
INSERT INTO NUMBERS (id) VALUES (NULL);
Setelah Anda memiliki NUMBERS
tabel, Anda dapat menggunakan:
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'
Solusi berteknologi rendah mutlak adalah:
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
Untuk menghasilkan daftar tanggal atau nomor agar KIRI BERGABUNG ke. Anda akan melakukannya untuk melihat di mana ada celah dalam data, karena Anda KIRI BERGABUNG ke daftar data berurutan - nilai null akan memperjelas di mana ada celah.
DUAL
table didukung oleh Oracle dan MySQL untuk digunakan sebagai stand-in meja di FROM
klausa. Itu tidak ada, memilih nilai darinya akan mengembalikan apa pun nilainya. Idenya adalah untuk memiliki stand-in karena query SELECT memerlukan FROM
klausa yang menentukan setidaknya satu tabel.
Untuk Access 2010 - diperlukan beberapa langkah; Saya mengikuti pola yang sama seperti yang diposting di atas, tetapi saya pikir saya dapat membantu seseorang di Access. Bekerja dengan baik untuk saya, saya tidak harus menyimpan tabel tanggal unggulan.
Buat tabel bernama DUAL (mirip dengan cara kerja tabel Oracle DUAL)
Buat kueri bernama "ZeroThru9Q"; masukkan sintaks berikut secara manual:
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;
Buat kueri bernama "TodayMinus1KQ" (untuk tanggal sebelum hari ini); masukkan sintaks berikut secara manual:
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
Buat kueri bernama "TodayPlus1KQ" (untuk tanggal setelah hari ini); masukkan sintaks berikut secara manual:
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;
Buat kueri gabungan bernama "TodayPlusMinus1KQ" (untuk tanggal +/- 1000 hari):
SELECT MyDate
FROM TodayMinus1KQ
UNION
SELECT MyDate
FROM TodayPlus1KQ;
Sekarang Anda dapat menggunakan kueri:
SELECT MyDate
FROM TodayPlusMinus1KQ
WHERE MyDate BETWEEN #05/01/2014# and #05/30/2014#
Prosedur + tabel sementara:
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
thx Pentium10 - Anda membuat saya bergabung dengan stackoverflow :) - ini adalah porting saya ke msaccess - pikir ini akan berfungsi pada versi apa pun:
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 yang direferensikan hanya karena akses memerlukan tabel yang menghitung setidaknya 1 record, dalam klausa from - tabel apa pun dengan minimal 1 record akan dilakukan.
Seperti yang dinyatakan (atau setidaknya disinggung) di banyak jawaban luar biasa yang telah diberikan, masalah ini mudah diselesaikan setelah Anda memiliki serangkaian angka untuk dikerjakan.
Catatan: Berikut ini adalah T-SQL tetapi ini hanyalah implementasi khusus dari konsep umum saya yang sudah disebutkan di sini dan di internet secara luas. Seharusnya relatif sederhana untuk mengubah kode ke dialek pilihan Anda.
Bagaimana? Pertimbangkan pertanyaan ini:
SELECT DATEADD(d, N, '0001-01-22')
FROM Numbers -- A table containing the numbers 0 through N
WHERE N <= 5;
Di atas menghasilkan rentang tanggal 1/22/0001 - 1/27/0001 dan sangat sepele. Ada 2 buah kunci informasi dalam query di atas: tanggal mulai dari 0001-01-22
dan mengimbangi dari 5
. Jika kita menggabungkan kedua informasi ini, maka jelas kita memiliki tanggal akhir. Jadi, dengan dua tanggal, menghasilkan rentang dapat dipecah seperti ini:
Temukan perbedaan antara dua tanggal tertentu (offset), mudah:
-- Returns 125
SELECT ABS(DATEDIFF(d, '2014-08-22', '2014-12-25'))
Menggunakan di ABS()
sini memastikan bahwa urutan tanggal tidak relevan.
Hasilkan serangkaian angka terbatas, juga mudah:
-- 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')
Perhatikan bahwa kami sebenarnya tidak peduli dengan apa yang kami pilih di FROM
sini. Kami hanya perlu satu set untuk bekerja sehingga kami menghitung jumlah baris di dalamnya. Saya pribadi menggunakan TVF, beberapa menggunakan CTE, yang lain menggunakan tabel angka, Anda mengerti. Saya menganjurkan untuk menggunakan solusi paling berkinerja yang juga Anda pahami.
Menggabungkan kedua metode ini akan menyelesaikan masalah kita:
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));
Contoh di atas adalah kode yang mengerikan tetapi menunjukkan bagaimana semuanya menjadi satu.
Lebih menyenangkan
Saya perlu melakukan banyak hal seperti ini jadi saya merangkum logika menjadi dua TVF. Yang pertama menghasilkan rentang angka dan yang kedua menggunakan fungsi ini untuk menghasilkan rentang tanggal. Perhitungannya adalah untuk memastikan bahwa urutan input tidak penting dan karena saya ingin menggunakan berbagai angka yang tersedia di GenerateRangeSmallInt
.
Fungsi berikut membutuhkan ~ 16ms waktu CPU untuk mengembalikan kisaran maksimum 65536 tanggal.
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
);
coba ini.
SELECT TO_DATE('20160210','yyyymmdd') - 1 + LEVEL AS start_day
from DUAL
connect by level <= (TO_DATE('20160228','yyyymmdd') + 1) - TO_DATE('20160210','yyyymmdd') ;
Anda ingin mendapatkan rentang tanggal.
Dalam contoh Anda, Anda ingin mendapatkan tanggal antara '2010-01-20' dan '2010-01-24'
solusi yang mungkin:
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'
Penjelasan
MySQL memiliki fungsi date_add
select date_add('2010-01-20', interval 1 day)
akan memberimu
2010-01-21
Fungsi Dateiff akan memberi tahu Anda bahwa Anda harus sering mengulanginya
select datediff('2010-01-24', '2010-01-20')
yang kembali
4
Mendapatkan daftar tanggal dalam rentang tanggal bermuara pada membuat urutan bilangan bulat lihat menghasilkan urutan bilangan bulat di MySQL
Jawaban yang paling banyak disukai di sini menggunakan pendekatan yang mirip dengan https://stackoverflow.com/a/2652051/1497139 sebagai dasarnya:
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
yang akan menghasilkan
row
1.0
2.0
3.0
4.0
Baris sekarang dapat digunakan untuk membuat daftar tanggal dari tanggal mulai tertentu. Untuk memasukkan tanggal mulai kita mulai dengan baris -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'
jika Anda membutuhkan lebih dari beberapa hari, Anda membutuhkan meja.
kemudian,
select from days.day, count(mytable.field) as fields from days left join mytable on day=date where date between x and y;
Berikut ini contohnya
Kami memiliki tanggal dalam satu tabel
Nama Tabel: "tanggal ujian"
STARTDATE ENDDATE
10/24/2012 10/24/2012
10/27/2012 10/29/2012
10/30/2012 10/30/2012
Membutuhkan Hasil:
STARTDATE
10/24/2012
10/27/2012
10/28/2012
10/29/2012
10/30/2012
Larutan:
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
Penjelasan: Penjelasan kueri rekursif CTE
Bagian pertama dari query:
SELECT DISTINCT convert(varchar(10), StartTime, 101) AS StartTime, datediff(dd, StartTime, endTime) AS diff FROM dbo.testdate
Penjelasan: firstcolumn is “startdate”, kolom kedua adalah selisih tanggal mulai dan tanggal akhir dalam hari dan akan dianggap sebagai kolom “diff”
Bagian kedua dari kueri:
UNION ALL SELECT StartTime, diff-1 AS diff FROM CTE WHERE diff<>0
Penjelasan: Gabungan semua akan mewarisi hasil kueri di atas sampai hasilnya menjadi nol, Jadi "Waktu Mulai" hasil diwarisi dari kueri CTE yang dihasilkan, dan dari diff, kurangi - 1, jadi terlihat seperti 3, 2, dan 1 sampai 0
Sebagai contoh
STARTDATE DIFF
10/24/2012 0
10/27/2012 0
10/27/2012 1
10/27/2012 2
10/30/2012 0
Spesifikasi Hasil
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
Bagian ke-3 dari Query
SELECT DISTINCT DateAdd(dd,diff, StartTime) AS StartTime FROM CTE
Ini akan menambahkan hari "diff" di "startdate" jadi hasilnya harus seperti di bawah ini
Hasil
STARTDATE
10/24/2012
10/27/2012
10/28/2012
10/29/2012
10/30/2012
Jawaban yang lebih pendek dari yang diterima, ide yang sama:
(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')
Untuk siapa saja yang menginginkan ini sebagai tampilan tersimpan (MySQL tidak mendukung pernyataan pemilihan bersarang dalam tampilan):
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;
Anda kemudian bisa melakukannya
select * from date_range
mendapatkan
date
---
2017-06-06
2017-06-05
2017-06-04
2017-06-03
2017-06-02
...
Solusi elegan menggunakan fungsionalitas rekursif (Common Table Expressions) baru di MariaDB> = 10.3 dan 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;
Di atas mengembalikan tabel tanggal antara '2019-01-01' dan '2019-04-30'. Ini juga cukup cepat. Mengembalikan tanggal senilai 1000 tahun (~ 365.000 hari) membutuhkan waktu sekitar 400ms di mesin saya.
Ada baiknya membuat tanggal-tanggal ini dengan cepat. Namun, saya tidak merasa nyaman melakukan ini dengan jangkauan yang cukup besar sehingga saya berakhir dengan solusi berikut:
CREATE TABLE DatesNumbers (
i MEDIUMINT NOT NULL,
PRIMARY KEY (i)
)
COMMENT='Used by Dates view'
;
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
;
SELECT
i,
CURRENT_DATE() + INTERVAL i DAY AS Date
FROM
DatesNumbers
Itu dia.
WHERE i < 0
atau WHERE i > 0
(PK)Baiklah .. Coba ini:
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
Gunakan itu untuk, katakanlah, menghasilkan tabel temp, lalu lakukan pemilihan * pada tabel temp. Atau keluarkan hasil satu per satu.
Apa yang Anda katakan ingin Anda lakukan tidak dapat dilakukan dengan pernyataan SELECT , tetapi mungkin dapat dilakukan dengan hal-hal khusus untuk MySQL.
Kemudian lagi, mungkin Anda membutuhkan kursor: http://dev.mysql.com/doc/refman/5.0/en/cursors.html
Untuk Oracle, solusi saya adalah:
select trunc(sysdate-dayincrement, 'DD')
from dual, (select level as dayincrement
from dual connect by level <= 30)
Sysdate dapat diubah menjadi tanggal tertentu dan nomor level dapat diubah untuk memberikan lebih banyak tanggal.
jika Anda ingin daftar tanggal antara dua tanggal:
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
* biola di sini: http://sqlfiddle.com/#!6/9eecb/3469
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)
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()
);
Versi SQLite dari solusi teratas RedFilters
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
ditingkatkan dengan hari kerja dan bergabung dengan tabel hari libur khusus microsoft MSSQL 2012 untuk tabel tanggal 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)
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'
Dapat membuat prosedur juga untuk membuat tabel kalender dengan peta waktu yang berbeda dari hari. Jika Anda menginginkan meja untuk setiap kuartal
misalnya
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
kamu bisa memakai
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
dan kemudian memanipulasinya
select ts, dt from calendar_table_tmp;
yang memberi Anda juga 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'
dari sini Anda dapat mulai menambahkan informasi lain seperti
select ts, dt, weekday(dt) as wd from calendar_table_tmp;
atau buat tabel nyata dengan membuat pernyataan tabel
Jawaban yang lebih umum yang berfungsi di 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
Satu lagi solusi untuk mysql 8.0.1 dan mariadb 10.2.2 menggunakan ekspresi tabel umum rekursif:
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;