Я создал представление SQL с помощью Management Studio. Представление объединяет несколько таблиц вместе и доступно для моего приложения MVC. Таблицы относятся к аренде автомобилей. Одна таблица содержит сведения об автомобиле, а другая - информацию о бронировании, которые объединяются с помощью представления.
Просмотр работает без проблем, но меня попросили также добавить столбец, который показывает следующее немедленное бронирование, которое есть у автомобиля. Это означает, что мне нужен столбец, чтобы показать дату начала следующего бронирования, где совпадает идентификатор автомобилей.
Таблица: Автомобили
Таблица: бронирования
Просмотр: CarBookings
SELECT [C].[Id],
[C].[Registration],
[C].[Make],
[C].[Model],
[B].[BookingStartDate],
[B].[BookingEndDate]
FROM [Cars] AS C INNER JOIN [Bookings] AS B ON C.Id = B.CarId
Как я могу добавить в свое представление столбец, в котором будет отображаться следующее бронирование, которое у машины есть? Любая помощь приветствуется.
Не могли бы вы подробнее рассказать о «следующем немедленном бронировании»? Как работает эта логика? Где это хранится? Какие данные у вас есть на этот случай? Ваш текущий sql должен просто получить все согласованные экземпляры между вашими автомобилями и бронированиями, что означает, что вы также по умолчанию получите «следующее немедленное бронирование» по умолчанию, если оно сохранено в таблице бронирования?
Из вопроса кажется, что вам нужно первое бронирование в текущую дату и время или позже? Если да, то вы можете использовать ВЕРХ или ПРЕДЕЛ с заказом на. Но этот синтаксис скорее зависит от базы данных. Так что вы можете добавить тег для нужного вам типа базы данных.
Вы хотите показать только информацию об автомобиле и следующее предстоящее бронирование? (Как уже упоминалось, в вашем текущем запросе в настоящее время отображаются все бронирования, старые и новые)


Используйте LEAD() (sql server 2012 и новее)
select c.*, b.BookingStartDate, b.BookingEndDate,
lead(bookingstartdate) over (partition by carid order by BookingStartDate) as nextbooking
from cars c
inner join bookings b
on c.id = b.carid
Мне нравится идея использовать LEAD (если он доступен), но я думаю, вам нужно как-то ограничить свой запрос, чтобы возвращалась только последняя запись о бронировании (в настоящее время он возвращает все).
Я тоже так думаю, просто пропущена запятая после b.BookingEndDate, и вы имеете в виду BookingEndDate вместо date?
@TimBiegeleisen Вопрос неясен по этому поводу, поэтому обеспечивает целостное представление
Вот запрос, который должен дать желаемые результаты. В CTE я использую сводный запрос, чтобы получить самую последнюю и вторую по времени запись о бронировании для каждого CarId. Затем мы присоединяем этот CTE к таблице Car аналогично тому, как вы это уже делали.
WITH cte AS (
SELECT
CarId,
MAX(CASE WHEN rn = 1 THEN BookingStartDate END) AS BookingStartDate,
MAX(CASE WHEN rn = 1 THEN BookingEndDate END) AS BookingEndDate,
MAX(CASE WHEN rn = 2 THEN BookingStartDate END) AS NextBookingStartDate,
MAX(CASE WHEN rn = 2 THEN BookingEndDate END) AS NextBookingEndDate
FROM
(
SELECT CarId, BookingStartDate, BookingEndDate,
ROW_NUMBER() OVER (PARTITION BY CarId ORDER BY BookingStartDate DESC) rn
FROM Bookings
) t
WHERE rn <= 2
GROUP BY CarId
)
SELECT
c.Id,
c.Registration,
c.Make,
c.Model,
b.BookingStartDate,
b.BookingEndDate,
b.NextBookingStartDate,
b.NextBookingEndDate
FROM Cars c
INNER JOIN cte b
ON c.Id = b.CarId;
Как сказал Тим в комментариях, ваш запрос уже дает вам все бронирования, но если вам нужно в другом столбце, то, возможно, вам нужен lead()?
SELECT C.Id,
B.BookingStartDate,
B.BookingEndDate,
lead(BookingStartDate) over(partition by C.Id order by B.BookingEndDate) nextdt
FROM Cars AS C INNER JOIN Bookings AS B ON C.Id = B.CarId
Ниже запрос предоставит все предстоящие заказы на конкретный автомобиль. Если вам нужен только следующий, вам следует использовать Row_number.
SELECT [C].[Id],
[C].[Registration],
[C].[Make],
[C].[Model],
[B].[BookingStartDate],
[B].[BookingEndDate]
FROM [Cars] AS C
INNER JOIN [Bookings] AS B ON C.Id = B.CarId
WHERE [B].[BookingStartDate] >= GETDATE()
ORDER BY [B].[BookingStartDate]
Если существующее представление делает то, что вы хотите (это все комбинации автомобилей и бронирований, кроме машин без бронирований, так как вы использовали внутреннее соединение), и вы просто хотите спроецировать "следующий" порядок, который, как я предполагаю, ссылается на текущую дату и время,
вы можете добавить левое соединение к запросу, который извлекает «следующее» бронирование для каждой машины и создает столбец, который определяет его, когда оно соответствует следующей записи.
Логика левого соединения:
Присоединяйтесь - по дате бронирования и carId (теперь, если будет два одинаковых бронирований на машину, вы получите оба в следующем матче, так как присоединитесь к условие будет применяться к обоим).
select
a.* ,
b.* ,
case when c.carId is not null then 1 else 0 end as IsNext
from cars a
inner join bookings b
on a.id = b.carid
left join (select carid , min(bookingStartDate) bookingStartDate from bookings where bookingStartDate > now() group by carid) c
on b.carId = c.carId
and b.bookingStartDate = c.bookingStartDate
комментарий: этот ответ - синтаксис postgres, поскольку вы не указали, какую базу данных вы используете. если это sql-сервер - замените now () на GETDATE ()
Я не вижу никакой логики для определения того, какое первое бронирование отображается. В вашем текущем представлении будет отображаться все бронирований для данного автомобиля. Здесь могут помочь некоторые образцы данных.