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 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
7,4357 gold badges38 silver badges58 bronze badges
answered May 31, 2011 at 11:45
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
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 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 BacklundAndre Backlund
6,8253 gold badges20 silver badges27 bronze badges
SELECT event_id FROM Table ORDER BY EVENT_START_DATE LIMIT 3
animuson♦
53.6k28 gold badges137 silver badges147 bronze badges
answered May 31, 2011 at 11:41
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