SQL Выберите все даты в диапазоне, даже если они не существуют без выделенной таблицы [duplicate]

Что вы должны сделать:

Добавить конструктор в ваш суперкласс:

public Superclass {
    public SuperClass(String flavour) {
       // super class constructor
       this.flavour = flavour;
    }
}

В классе Crisps:

public Crisps(String flavour, int quantity) {
    super(flavour); // send flavour to the super class constructor
    this.quantity = quantity;
}

& nbsp;

Комментарии

Некоторые комментарии к вашему вопросу:

«В суперклассе я инициализировал поле с помощью«

private String flavour;

не является инициализацией, это декларация. Инициализация - это когда вы устанавливаете значение.

«Я получаю сообщение об ошибке» имеет личный доступ в суперклассе », но я считаю, что это не имеет значения, поскольку я вызываю метод доступа, который возвращает его поле? "

Когда вы вызываете аксессуар (aka getter), это нормально - зависит от видимости геттера. Проблема в вашем коде:

this.flavour = 

, потому что аромат не является полем, объявленным в классе Crisps, но в классе ужина, поэтому вы не можете делать прямой доступ. вы должны использовать мое предложение или объявить сеттера в суперклассе:

public void setFlavour(String flavour) {
    this.flavour = flavour;
}

Затем вы можете использовать его в дочернем классе:

public Crisps(String flavour, int quantity) {
    this.quantity = quantity;
    super.setFlavour(flavour);
}
117
задан Pentium10 29 January 2010 в 07:10
поделиться

22 ответа

Это решение не использует циклы, процедуры или временные таблицы. Подзапрос генерирует даты в течение последних тысяч дней и может быть расширен, чтобы идти как можно дальше или вперед по вашему желанию.

select a.Date 
from (
    select curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.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
) 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 сек.

Если мы расширим подзапрос, чтобы создать ок. 100000 номеров (и, следовательно, даты дат 274 года), он работает в 0,0458 сек.

Кстати, это очень портативный метод, который работает с большинством баз данных с небольшими корректировками.

Пример SQL Fiddle, возвращающий 1000 дней

279
ответ дан RedFilter 27 August 2018 в 06:19
поделиться
  • 1
    +1 для одного из самых сюрреалистических запросов, которые я когда-либо видел. – Lluis Martinez 28 January 2010 в 21:58
  • 2
    Вы увидите лучшую производительность, если вы измените UNION на UNION ALL - он тратит время на проверку дубликатов для удаления, которых не существует. Это слишком сложная ИМО, хотя, если вы собираетесь создавать набор результатов с помощью UNION, почему бы просто не указать дату и не сделать с ней? – OMG Ponies 28 January 2010 в 22:27
  • 3
    почему бы просто не указать дату и сделать с ней - потому что вышеупомянутый метод позволяет создавать произвольно большие наборы чисел (и дат), не требующих создания таблицы, что было бы болезненно для жесткого кода в как вы предлагаете. Очевидно, что за 5 дат это слишком много; но даже тогда, если вы присоединяетесь к таблице, где вы не знаете даты заранее, а только о потенциальных значениях min и max, это имеет смысл. – RedFilter 28 January 2010 в 23:10
  • 4
    Очень приятно видеть ответ на вопрос, а не бесконечные комментарии, как это невозможно или не должно быть сделано. Большинство вещей можно сделать, и "должен" имеет смысл только в контексте, который отличается для каждого. Этот ответ помог мне, хотя я хорошо знаю, что в большинстве ситуаций есть лучшие способы. – joe 30 May 2012 в 01:58
  • 5
    Те из вас, кто не может заставить этот запрос работать: пожалуйста, ударитесь в лицо, а затем перечитайте комментарий OP о том, что этот запрос генерирует 1000 дат. С 2010 года было более 1000 дней назад, вам нужно будет соответствующим образом настроить запрос. – Noel Baron 8 February 2015 в 10:30

, если вам нужен список дат между двумя датами:

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
ответ дан celerno 27 August 2018 в 06:19
поделиться

, если вам понадобится больше двух дней, вам понадобится таблица.

Создайте диапазон дат в mysql

, затем

select from days.day, count(mytable.field) as fields from days left join mytable on day=date where date between x and y;
1
ответ дан Community 27 August 2018 в 06:19
поделиться
  • 1
    почему вы разместили это, так как вышеприведенный ответ не нуждается в таблице и предоставляет решение? – Pentium10 29 January 2010 в 14:44

Короче принятого ответа, та же идея:

(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
ответ дан daniherculano 27 August 2018 в 06:19
поделиться

Принятый ответ не работал для 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)
18
ответ дан Dmitry Gusev 27 August 2018 в 06:19
поделиться

Это хорошая идея, чтобы генерировать эти даты на лету. Тем не менее, я не чувствую себя комфортно для этого с довольно большим диапазоном, поэтому я получил следующее решение:

  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)
  • (-) «временная» таблица & amp; вид используется
0
ответ дан fifonik 27 August 2018 в 06:19
поделиться

Используя рекурсивное выражение общей таблицы (CTE), вы можете создать список дат, а затем выбрать из него. Очевидно, вы обычно не хотели бы создавать три миллиона дат, поэтому это просто иллюстрирует возможности. Вы можете просто ограничить диапазон дат внутри CTE и опустить предложение where из оператора 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. Генерация столетий заняла менее секунды.

12
ответ дан Joshua 27 August 2018 в 06:19
поделиться

улучшилось с буднего дня, присоединившись к специальной праздничной таблице 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
ответ дан josy1024 27 August 2018 в 06:19
поделиться

Как было сказано (или, по крайней мере, намечено) во многих замечательных ответах, уже заданных, эта проблема легко решается после того, как у вас есть набор чисел для работы.

Примечание: / g0] Ниже приводится 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 и является чрезвычайно тривиальным. В приведенном выше запросе есть две ключевые части информации: дата начала 0001-01-22 и смещение в 5. Если мы объединим эти две части информации, мы, очевидно, имеем дату окончания. Таким образом, учитывая две даты, генерация диапазона может быть разбита так:

  • Найти разницу между двумя заданными датами (смещение), easy: -- 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));

Вышеприведенный пример - ужасный код, но демонстрирует, как все объединяется.

More Fun

Мне нужно много чего делать, поэтому я инкапсулировал логику в два TVF. Первый генерирует ряд чисел, а второй использует эту функцию для создания диапазона дат. Математика заключается в том, чтобы гарантировать, что порядок ввода не имеет значения, и потому, что я хотел использовать полный диапазон чисел, доступных в GenerateRangeSmallInt.

Следующая функция занимает ~ 16 мс времени процессора, чтобы вернуть максимальный диапазон из 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
);
1
ответ дан Kittoes0124 27 August 2018 в 06:19
поделиться

попробуйте это.

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
ответ дан loalexzzzz 27 August 2018 в 06:19
поделиться

Процедура + временная таблица:

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
2
ответ дан Márcio Souza Júnior 27 August 2018 в 06:19
поделиться

Версия SQLite решения RedFilters top

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
ответ дан martin 27 August 2018 в 06:19
поделиться
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
ответ дан Mogsdad 27 August 2018 в 06:19
поделиться

Для Oracle мое решение:

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

Sysdate можно изменить на определенную дату, а номер уровня можно изменить, чтобы указать больше дат.

0
ответ дан mousetwentytwo 27 August 2018 в 06:19
поделиться

Создание дат между двумя полями даты

Если вам известно о запросе 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 Объяснение: Союз все наследует результат вышеуказанного запроса до результата имеет значение null, поэтому результат «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
  • Третья часть запроса SELECT DISTINCT DateAdd(dd,diff, StartTime) AS StartTime FROM CTE Она добавит день «diff» в «startdate», поэтому результат Shou ld будет ниже

Результат

STARTDATE
10/24/2012
10/27/2012
10/28/2012
10/29/2012
10/30/2012
4
ответ дан omegastripes 27 August 2018 в 06:19
поделиться

Старое решение школы для этого без цикла / курсора состоит в создании таблицы NUMBERS, которая имеет один столбец Integer со значениями, начинающимися с 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'

Абсолютное низкотехнологичное решение be:

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 JOINING в список секвенциальных данных - нулевые значения станут очевидными там, где существуют пробелы.

4
ответ дан OMG Ponies 27 August 2018 в 06:19
поделиться
  • 1
    что dual? – Pentium10 29 January 2010 в 00:07
  • 2
    Таблица DUAL поддерживается Oracle и MySQL для использования в качестве таблицы stand-in в предложении FROM. Он не существует, выбор значений из него будет возвращать все значения. Идея заключалась в том, чтобы иметь stand-in, потому что для запроса SELECT требуется предложение FROM, определяющее хотя бы одну таблицу. – OMG Ponies 29 January 2010 в 00:17
  • 3
    +1 для фактического создания таблицы постоянных чисел вместо того, чтобы создавать РСУБД с ее помощью каждый раз, когда вам нужен запрос. Вспомогательные столы не злые, люди! – Bacon Bits 13 April 2015 в 13:39

Вот еще одна вариация, использующая представления:

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;
30
ответ дан Stéphane 27 August 2018 в 06:19
поделиться
  • 1
    Это не работает во всех случаях. SELECT date FROM date WHERE date BETWEEN '2014-12-01' AND '2014-12-28' ORDER BY date – vasanth 8 December 2013 в 01:09
  • 2
    Хороший звонок @ user927258. Это связано с тем, что первый вид dates, упомянутый выше, вычисляет даты, начинающиеся с текущей даты, поэтому вы не сможете получить даты, установленные в будущем. Ответ от @RedFilter страдает от того же дефекта дизайна. Однако я добавил обходной путь в свой ответ. – Stéphane 22 December 2013 в 23:09
  • 3
    Очень хорошо работает – phpmysqlguy 31 December 2014 в 20:03
  • 4
    Использование некоторых представлений определенно упрощает запросы и делает их многоразовыми. Хотя они по сути делают одно и то же, все эти предложения UNION выглядят странно в одном выражении SQL. – Stewart 6 September 2016 в 16:51

Запрос 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
7
ответ дан SUHAIL AG 27 August 2018 в 06:19
поделиться
  • 1
    Если бы я только прокрутил немного больше ... вздохнул. В любом случае, спасибо. Я добавил CAST (& lt; выражение & gt; AS DATE), чтобы удалить время в моей версии. Также используется где a.Date между GETDATE () - 365 И GETDATE () ... если вы запустите свой запрос сегодня, он не даст строк, если вы не заметите даты в WHERE = P – Ricardo C 24 March 2016 в 22:39

Для всех, кто хочет это как сохраненное представление (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

, чтобы get

date
---
2017-06-06
2017-06-05
2017-06-04
2017-06-03
2017-06-02
...
1
ответ дан Tom G 27 August 2018 в 06:19
поделиться

Хорошо .. Попробуйте следующее: http://www.devshed.com/c/a/MySQL/Delving-Deeper-into-MySQL-50/ http: // dev .mysql.com / doc / refman / 5.0 / ru / loop-statement.html http://www.roseindia.net/sql/mysql-example/mysql-loop.shtml

Используйте это, чтобы, скажем, создать временную таблицу, а затем сделать select * в таблице temp. Или выводить результаты по одному. То, что вы говорите, что вы хотите сделать, не может быть сделано с помощью инструкции SELECT , но это может быть выполнимо с вещами, специфичными для MySQL. Опять же, возможно, вам нужны курсоры: http://dev.mysql.com/doc/refman/5.0/en/cursors.html

0
ответ дан Trevoke 27 August 2018 в 06:19
поделиться

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]);

, на который ссылаются MSysObjects, просто потому, что для доступа нужен стол countin 'по крайней мере 1 запись, в условии from - любая таблица с не менее чем 1 записью.

3
ответ дан user3780177 27 August 2018 в 06:19
поделиться
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
ответ дан Victor Silva 27 August 2018 в 06:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: