Sql как найти ближайшую дату

I have a better solution for this problem i think.

I will show a few images to support and explain the final solution.

Background
In my solution I have a table of FX Rates. These represent market rates for different currencies. However, our service provider has had a problem with the rate feed and as such some rates have zero values. I want to fill the missing data with rates for that same currency that as closest in time to the missing rate. Basically I want to get the RateId for the nearest non zero rate which I will then substitute. (This is not shown here in my example.)

1) So to start off lets identify the missing rates information:

Query showing my missing rates i.e. have a rate value of zero

2) Next lets identify rates that are not missing.
Query showing rates that are not missing

3) This query is where the magic happens. I have made an assumption here which can be removed but was added to improve the efficiency/performance of the query. The assumption on line 26 is that I expect to find a substitute transaction on the same day as that of the missing / zero transaction.
The magic happens is line 23: The Row_Number function adds an auto number starting at 1 for the shortest time difference between the missing and non missing transaction. The next closest transaction has a rownum of 2 etc.

Please note that in line 25 I must join the currencies so that I do not mismatch the currency types. That is I don’t want to substitute a AUD currency with CHF values. I want the closest matching currencies.

Combining the two data sets with a row_number to identify nearest transaction

4) Finally, lets get data where the RowNum is 1
The final query

The query full query is as follows;

    ; with cte_zero_rates as
(
        Select      * 
        from        fxrates
        where       (spot_exp = 0 or spot_exp = 0) 
),
cte_non_zero_rates as
(
        Select      * 
        from        fxrates
        where       (spot_exp > 0 and spot_exp > 0) 
)
,cte_Nearest_Transaction as
(
        select       z.FXRatesID    as Zero_FXRatesID
                    ,z.importDate   as Zero_importDate
                    ,z.currency     as Zero_Currency
                    ,nz.currency    as NonZero_Currency
                    ,nz.FXRatesID   as NonZero_FXRatesID
                    ,nz.spot_imp
                    ,nz.importDate  as NonZero_importDate
                    ,DATEDIFF(ss, z.importDate, nz.importDate) as TimeDifferece
                    ,ROW_NUMBER() Over(partition by z.FXRatesID order by abs(DATEDIFF(ss, z.importDate, nz.importDate)) asc) as RowNum
        from        cte_zero_rates z 
        left join   cte_non_zero_rates nz on nz.currency = z.currency
                    and cast(nz.importDate as date) = cast(z.importDate as date)
        --order by  z.currency desc, z.importDate desc
)
select           n.Zero_FXRatesID
                ,n.Zero_Currency
                ,n.Zero_importDate
                ,n.NonZero_importDate
                ,DATEDIFF(s, n.NonZero_importDate,n.Zero_importDate) as Delay_In_Seconds
                ,n.NonZero_Currency
                ,n.NonZero_FXRatesID
 from           cte_Nearest_Transaction n
 where          n.RowNum = 1
                and n.NonZero_FXRatesID is not null
 order by       n.Zero_Currency, n.NonZero_importDate

I’m trying to figure out how to write a MySQL query that will return the closest 3 events in terms of date.

This is my table:

EVENT_ID    EVENT_NAME     EVENT_START_DATE(DATETIME)
1           test           2011-06-01 23:00:00
2           test2          2011-06-03 23:00:00
3           test3          2011-07-01 23:00:00
4           test4          2011-08-09 23:00:00
5           test5          2011-06-02 23:00:00
6           test6          2011-04-20 23:00:00

So the query result should be for ID’s 1,2,5 as they are the closest to occur in comparison to the current date..

EDIT: query should find only future events.

asked May 31, 2011 at 11:37

Or Weinberger's user avatar

Or WeinbergerOr Weinberger

7,31220 gold badges70 silver badges116 bronze badges

2

SELECT event_id 
FROM Table 
ORDER BY ABS( DATEDIFF( EVENT_START_DATE, NOW() ) ) 
LIMIT 3

The ABS() means that an event 1 day ago is just as close as an event 1 day in the future. If you only want events that haven’t happened yet, do

SELECT event_id 
FROM Table 
WHERE EVENT_START_DATE > NOW() 
ORDER BY EVENT_START_DATE 
LIMIT 3 

bancer's user avatar

bancer

7,4357 gold badges38 silver badges58 bronze badges

answered May 31, 2011 at 11:45

Mat's user avatar

MatMat

6,6657 gold badges34 silver badges39 bronze badges

1

  SELECT *
    FROM table
   WHERE EVENT_START_DATE >= NOW()
ORDER BY EVENT_START_DATE
   LIMIT 3

answered May 31, 2011 at 11:43

hsz's user avatar

hszhsz

147k61 gold badges258 silver badges313 bronze badges

The query from accepted answer actually just sort previously selected values, not filter them before select. But this query works for me:

SELECT event_id, event_date
FROM events 
WHERE ABS(TIMESTAMPDIFF(DAY, event_date, $some_date)) < 10
ORDER BY event_date

Explanation: number 10 is a day range (both after and before). Without ABS() you can select only previous or future events, but I needed the closest.

answered Aug 26, 2018 at 15:58

Damjan Pavlica's user avatar

Damjan PavlicaDamjan Pavlica

30.5k10 gold badges71 silver badges76 bronze badges

I suppose this is what you’d be looking for. It’s similar to everyone elses responses aswell.

SELECT EVENT_ID FROM TABLE WHERE EVENT_START_DATE > NOW() ORDER BY ABS(DATEDIFF(EVENT_START_DATE, NOW())) ASC LIMIT 3

answered May 31, 2011 at 11:50

Andre Backlund's user avatar

Andre BacklundAndre Backlund

6,8253 gold badges20 silver badges27 bronze badges

SELECT event_id FROM Table ORDER BY EVENT_START_DATE LIMIT 3

animuson's user avatar

animuson

53.6k28 gold badges137 silver badges147 bronze badges

answered May 31, 2011 at 11:41

xecaps12's user avatar

xecaps12xecaps12

5,3163 gold badges27 silver badges42 bronze badges

2

У меня возникли проблемы с моим SQL-запросом.
Я получил эту таблицу:

insert into Table1 (date, personssn)
insert ('2012-01-21 12:01:33', '123456789');
insert into Table1 (date, personssn)
insert ('2012-02-22 12:01:33', '123456789');

Проблема в том, что я хочу выбрать людей, у которых есть дата CLOSEST, до текущей даты. Я работал с «CURDATE()», но, похоже, не может заставить его работать. Кто-нибудь, кто может помочь мне в правильном направлении?

Спасибо.

Вопрос:

У меня есть таблица dbo.X с DateTime column Y, которая может содержать сотни записей.

В моей хранимой процедуре есть параметр @CurrentDate, я хочу узнать дату в column Y в приведенной выше таблице dbo.X, которая меньше и ближе к @CurrentDate.

Как его найти?

Лучший ответ:

Предложение where будет соответствовать всем строкам с датой, меньшей чем @CurrentDate, и, поскольку они заказываются по наследству, TOP 1 будет ближайшей датой к текущей дате.

SELECT TOP 1 *
FROM x
WHERE x.date < @CurrentDate
ORDER BY x.date DESC

Ответ №1

Используйте DateDiff и закажите свой результат по количеству дней или секунд между этой датой и тем, что был входом

Что-то вроде этого

    select top 1 rowId, dateCol, datediff(second, @CurrentDate, dateCol) as SecondsBetweenDates
from myTable
where dateCol < @currentDate
order by datediff(second, @CurrentDate, dateCol)

Ответ №2

У меня есть лучшее решение для этой проблемы, я думаю.

Я покажу несколько изображений для поддержки и объяснения окончательного решения.

Фон
В моем решении у меня есть таблица курсов валют. Они представляют собой рыночные ставки для разных валют. Однако у нашего поставщика услуг возникла проблема с подачей ставки, и, как следствие, некоторые ставки имеют нулевые значения. Я хочу заполнить недостающие данные тарифами для той же самой валюты, которая как можно ближе к отсутствующей ставке. В принципе, я хочу получить RateId для ближайшей нулевой скорости, которую я затем заменим. (Это не показано здесь в моем примере.)

1) Итак, чтобы начать, укажите информацию о недостающих скоростях:

Запрос, показывающий мои недостающие ставки, то есть значение скорости, равное нулю

2) Далее указывается скорость, которую не хватает.
Запрос, показывающий скорости, которые не пропущены

3) Этот запрос – это то, где происходит волшебство. Я сделал здесь предположение, которое можно удалить, но было добавлено для повышения эффективности/производительности запроса. Предположение на строке 26 состоит в том, что я ожидаю найти заменяющую транзакцию в тот же день, что и транзакция с недостающим/нулевым.
Магия происходит в строке 23: Функция Row_Number добавляет автоматический номер, начинающийся с 1 для кратчайшего разницы во времени между отсутствующей и отсутствующей транзакцией. Следующая ближайшая транзакция имеет rownum из 2 и т.д.

Обратите внимание, что в строке 25 я должен присоединиться к валютам, чтобы я не рассортировал типы валют. То есть я не хочу подставлять валюту AUD значениями CHF. Я хочу, чтобы самые близкие соответствующие валюты.

Сочетание двух наборов данных с номером row_number для определения ближайшей транзакции

4) Наконец, давайте получим данные, где RowNum равен 1
Окончательный запрос

Запрос полного запроса выглядит следующим образом:

    ; with cte_zero_rates as
(
Select      *
from        fxrates
where       (spot_exp = 0 or spot_exp = 0)
),
cte_non_zero_rates as
(
Select      *
from        fxrates
where       (spot_exp > 0 and spot_exp > 0)
)
,cte_Nearest_Transaction as
(
select       z.FXRatesID    as Zero_FXRatesID
,z.importDate   as Zero_importDate
,z.currency     as Zero_Currency
,nz.currency    as NonZero_Currency
,nz.FXRatesID   as NonZero_FXRatesID
,nz.spot_imp
,nz.importDate  as NonZero_importDate
,DATEDIFF(ss, z.importDate, nz.importDate) as TimeDifferece
,ROW_NUMBER() Over(partition by z.FXRatesID order by abs(DATEDIFF(ss, z.importDate, nz.importDate)) asc) as RowNum
from        cte_zero_rates z
left join   cte_non_zero_rates nz on nz.currency = z.currency
and cast(nz.importDate as date) = cast(z.importDate as date)
--order by  z.currency desc, z.importDate desc
)
select           n.Zero_FXRatesID
,n.Zero_Currency
,n.Zero_importDate
,n.NonZero_importDate
,DATEDIFF(s, n.NonZero_importDate,n.Zero_importDate) as Delay_In_Seconds
,n.NonZero_Currency
,n.NonZero_FXRatesID
from           cte_Nearest_Transaction n
where          n.RowNum = 1
and n.NonZero_FXRatesID is not null
order by       n.Zero_Currency, n.NonZero_importDate

Ответ №3

CREATE PROCEDURE CurrentDate
@CurrentDate DATETIME
AS
BEGIN
Select * from orders
where OrderDate < @CurrentDate
END
GO

У меня проблема с объединением SQL-запроса, который должен показать мне ближайшую (предыдущую и следующую) дату от CURDATE().

У меня стол с клиентами и стол с ведьмами

Таблица с покупателями:

konto_odbiorcy | name
---------------+----------------
2              | Sony LTD
3              | Panasonic LTD
etc...

Вот что у меня есть в таблице с событиями:

number | date 
-------+-------------
2      | 2016-11-01
2      | 2016-11-06
2      | 2016-11-14
3      | 2016-11-02
3      | 2016-11-21
3      | 2016-11-26

Мне нужно знать, какова последняя прошедшая дата и следующая ближайшая дата в будущем, например:

number | date past   | date future
-------+-------------+-------------
2      | 2016-11-06  | 2016-11-14
3      | 2016-11-02  | 2016-11-21

Как видите, для number=3 покажите мне 2016-11-21 не 2016-11-26

Когда я хочу показать прошедшую ближайшую дату:

SELECT number, date AS past
FROM 3ce_event
WHERE date <= CURDATE()

На следующее мероприятие:

SELECT number, date AS future
FROM 3ce_event
WHERE date >= CURDATE()

Как теперь сравнить эти две таблицы с моими клиентами в одном SQL-запросе?

ИЗМЕНИТЬ

Я изменил свой запрос на ответ Майк :

select 
    number, klienci_ax_all.nazwa, miasto,
    max(case when date<=curdate() then date end) as date_past,
    min(case when date>=curdate() then date end) as date_future
from 3ce_event
inner join klienci_ax_all on 3ce_event.number = klienci_ax_all.konto_odbiorcy
group by konto_odbiorcy

Выглядит действительно хорошо, но у меня возникла проблема с таблицей клиентов (klienci_ax_all). Если для одного или нескольких клиентов нет ничего в таблице 3ce_event, у меня нет этого клиента как Null date_past и Null date_future.

Мне нужен полный список клиентов из klienci_ax_all, а также прошлые и будущие данные, если они существуют … любая помощь?

2 ответа

Лучший ответ

select number,
       max(case when date<=curdate() then date end) as date_past,
       min(case when date>=curdate() then date end) as date_future
  from event
 group by number


1

Mike
9 Ноя 2016 в 14:53

Один из способов сделать это — самостоятельно присоединиться к событиям, генерирующим подмножества для минимума / максимума каждой даты для каждой группы.

SELECT E.Number, E2.LTDate as `Date Past`, E1.GTDate as `Date Future`
FROM Events E
LEFT JOIN (SELECT number, min(date) GTDate 
           FROM events
           WHERE date >= CurDate 
           GROUP BY Number) E1
 on E.Number = E1.Number
LEFT JOIN (SELECT number, Max(date) LTDate 
           FROM events
           WHERE date <= CurDate 
           GROUP BY Number) E2
 on E.Number = E2.Number

Другой способ — использовать коррелированные встроенные запросы (выберите с / в выборе), чтобы найти минимальное / максимальное

SELECT E.Number
    , (Select max(E1.date) from events E1 where E1.Number = E.Number and E1.date<=sysdate)
    , (Select min(E1.date) from events E2 where E2.Number = E.Number and E2.date>=sysdate)
FROM Events E

Мне больше нравится 1-й подход, так как он не должен выполнять 3 запроса для каждой записи в таблице событий; однако на меньшем наборе данных второй может быть быстрее.


1

xQbert
9 Ноя 2016 в 14:26

Понравилась статья? Поделить с друзьями:

Не пропустите также:

  • Как найти к какой школе мы относимся
  • Как найти автора по нотам
  • Закончил вуз как найти работу
  • Как найти домашнее задание в электронном дневнике
  • Средство восстановления запуска не может автоматически восстановить этот компьютер как исправить

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии