質問
次のようなクエリを実行したいのですが
select ... as days where `date` is between '2010-01-20' and '2010-01-24'
そして、次のようなデータを返します。
days ---------- 2010-01-20 2010-01-21 2010-01-22 2010-01-23 2010-01-24
解決
このソリューションでは、 ループ、プロシージャ、または一時テーブルはありません. 。サブクエリは過去 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 秒で実行します。
ちなみに、これは非常に移植性の高い手法であり、わずかな調整を加えればほとんどのデータベースで動作します。
他のヒント
次に、ビューを使用した別のバリエーションを示します。
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;
受け入れ答えなかったPostgreSQLの作品(「」またはその近くの構文エラー)。
あなたは、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)
再帰共通テーブル式(CTE)を使用して、そこから選択し、日付のリストを生成することができます。もちろん、あなたは通常300万日付を作成したいとは思わないでしょう、これはただの可能性を示しています。あなたは、単にCTE内部の日付範囲を制限し、CTEを使用してselect文からwhere句を省略することができます。
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)
すべての可能な日付のCTEリストを生成するのMicrosoft SQL Server 2005年は、午前1時08分を要しました。百年の生成は少ない秒以上かかっています。
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
はループせずにこれを行うための古い学校のソリューション/カーソルは1から始まる値を持つ単一の整数列を持つNUMBERS
テーブルを作成することです。
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
あなたがのためにそれを使用するのでしょうか?
<時間> LEFTするために、日付または数値のリストを生成するには、へで登録しよう。あなたはLEFTは、連番のデータのリストに参加しているので、あなたは、データのギャップが存在する場所を確認するために、これになり - 。ギャップが存在する場合はnull値は、それが明らかになります。
アクセス2010の場合 - 複数の手順が必要です。私は上で投稿したのと同じパターンに従いましたが、Access で誰かを助けることができると考えました。私にとってはうまくいきました。日付のシードテーブルを保持する必要はありませんでした。
DUAL という名前のテーブルを作成します (Oracle DUAL テーブルの動作と同様です)。
- ID (オートナンバー)
- ダミーカラム (テキスト)
- 1 行の値を追加します (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」という名前のユニオン クエリを作成します (日付 +/- 1000 日の場合)。
SELECT MyDate
FROM TodayMinus1KQ
UNION
SELECT MyDate
FROM TodayPlus1KQ;
これで、次のクエリを使用できるようになります。
SELECT MyDate
FROM TodayPlusMinus1KQ
WHERE MyDate BETWEEN #05/01/2014# and #05/30/2014#
手順+一時テーブルます:
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 - あなたは:)私は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]);
単に「原因のアクセスが必要テーブルcountin」節から、少なくとも1件の記録、参照MSysObjects - 。どうなる少なくとも1つのレコードを持つテーブル
これを試してます。
SELECT TO_DATE('20160210','yyyymmdd') - 1 + LEVEL AS start_day
from DUAL
connect by level <= (TO_DATE('20160228','yyyymmdd') + 1) - TO_DATE('20160210','yyyymmdd') ;
あなたは今までに数日以上、その後必要になります場合は、あなたがテーブルを必要とします。
で日付範囲を作成します。そして、
select from days.day, count(mytable.field) as fields from days left join mytable on day=date where date between x and y;
すでに提供されている素晴らしい回答の多くで述べられているように (または少なくともほのめかされているように)、一連の数値を扱うことができれば、この問題は簡単に解決できます。
注記: 以下は 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
. 。これら 2 つの情報を組み合わせると、明らかに終了日が決まります。したがって、2 つの日付が与えられた場合、範囲の生成は次のように分類できます。
指定された 2 つの日付の差 (オフセット) を簡単に見つけます。
-- 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 を使用する人もいれば、代わりに数値テーブルを使用する人もいます。私は、あなたも理解している最もパフォーマンスの高いソリューションを使用することをお勧めします。
これら 2 つの方法を組み合わせると、問題が解決されます。
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));
上記の例はひどいコードですが、すべてがどのように連携するかを示しています。
もっと楽しく
このようなことを頻繁に行う必要があるため、ロジックを 2 つの TVF にカプセル化しました。1 つ目は数値の範囲を生成し、2 つ目はこの機能を使用して日付の範囲を生成します。この計算は、入力順序が重要ではないことを確認するためであり、使用可能な数値の全範囲を使用したかったためです。 GenerateRangeSmallInt
.
次の関数は、最大範囲の 65536 の日付を返すのに最大 16 ミリ秒の CPU 時間を要します。
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 つの日付フィールド間の日付を生成する
SQL CTE クエリに詳しい場合、このソリューションは質問の解決に役立ちます。
ここに例があります
1 つのテーブルに日付が含まれています
テーブル名:"試験日"
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」で、2番目の列は日の開始日と終了日の違いであり、「Diff」列と見なされますクエリの 2 番目の部分:
UNION ALL SELECT StartTime, diff-1 AS diff FROM CTE WHERE diff<>0
説明:ユニオンはすべて、結果がnullになるまで上記のクエリの結果を継承するため、「起動時」結果は生成されたCTEクエリから継承され、diff、減少-1であるため、3、2、および1のように見えます。
例えば
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
「startdate」に日の「diff」を追加するので、結果は以下のようになります。
結果
STARTDATE
10/24/2012
10/27/2012
10/28/2012
10/29/2012
10/30/2012
受け入れ答えよりも短く、同じ考えます:
(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')
(MySQLがビュー内のネストされたselect文をサポートしていません)保存されたビューとしてこれを望んでいる人のために:
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
...
日付範囲を取得したいとします。
あなたの例では、「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
の 日付差分 関数を使用すると、これを繰り返す必要があることがよくわかります
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'
これらの日付をその場で生成するのは良いアイデアです。ただし、非常に広い範囲でこれを行うのは快適ではないので、次の解決策に落ち着きました。
- 日付の計算に使用される数値を保持するテーブル「DatesNumbers」を作成しました。
CREATE TABLE DatesNumbers (
i MEDIUMINT NOT NULL,
PRIMARY KEY (i)
)
COMMENT='Used by Dates view'
;
- 上記の手法を使用してテーブルに -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
;
- ビュー「日付」を作成しました。
SELECT
i,
CURRENT_DATE() + INTERVAL i DAY AS Date
FROM
DatesNumbers
それでおしまい。
- (+) 読みやすいクエリ
- (+) オンザフライ番号世代なし
- (+) 過去と将来の日付を指定しますが、これには次のように UNION が表示されません。 この郵便受け.
- (+) 「過去のみ」または「将来のみ」の日付は、次を使用してフィルタリングできます。
WHERE i < 0
またはWHERE i > 0
(PK) - (-) 「一時的な」テーブルとビューが使用されます
さてさて。これを試してみてください。
http://www.devshed.com/c / A / MySQLの/探求と-ディーパー・イントゥ・MySQLの-50 / の
http://dev.mysql.com/doc/refman/ 5.0 / EN /ループstatement.html の
http://www.roseindia.net/sql/mysql-example/ mysqlの-loop.shtmlする
使用するようにその、一時テーブルを生成し、言って、その後、一時テーブル上のselect *を実行します。または出力結果一つずつ。
のあなたは、あなたがやりたいと言うが、SELECT文ので行うことはできませんが、それは、MySQLに物事の特定となんとかなるかもしれません。
その後、再び、多分あなたは、カーソルを必要とする:ます。http://dev.mysql。 COM / DOC / refman / 5.0 / EN / cursors.html の
Oracleの場合、私の解決策があります:
select trunc(sysdate-dayincrement, 'DD')
from dual, (select level as dayincrement
from dual connect by level <= 30)
SYSDATEは、特定の日付とレベル番号に変更することができますより多くの日数を与えるように変更することができます。
あなたは2つの日付の間の日付のリストをしたい場合:
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
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()
);
の SQLiteのの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
平日で改善のカスタム休日のテーブルに参加するを PowerPivotの日付テーブル2012 MSSQL のマイクロソフトの 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 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;
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'
エレガントなソリューション新しい再帰を使用して(共通テーブル式)機能> = 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年1月1日」と「2019年4月30日」の間の日付のテーブル。また、まともな高速です。日付(〜365,000日)1000年の価値を戻すと、私のマシン上で400msの程度かかります。
作成するプロシージャも作成できます カレンダーテーブル タイムマップ付き 日とは違う。四半期ごとのテーブルが必要な場合
例えば
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;
または実際のテーブルを作成します テーブル作成ステートメント