Страница 1 из 1
Странная проблема с left join
Добавлено: 30 июн 2007, 14:49
ARM
Наткнулся на проблему, которая меня поставила в штопор
Есть 2 таблицы:
- Пользователи (Users), где кроме других полей есть UserId
- Таблица логирования (log_UserSession), где есть также UserId, по кот. создан внешний ключ с Users.UserId
В таблице Users есть, допустим одна запись с UserId=1.
В таблице логирования есть 2 записи с UserId=1.
Делаю элементарный запрос:
select
u.userid
from users u
left join log_usersession us on us.userid=u.userid
и в результате получаю 2 записи с UserId=1 вместо 1-й из Users.
Может я не произнес какое-то заклинание ? В MS SQL отрабатывает на ура....
ЗЫ: FB 2.1 Alpha (может в Альфе проблема ?)
Добавлено: 01 июл 2007, 09:27
Attid
ну все правельно ты ведь их джойнишь, distict сделай если не нравится 2 записи =)
Добавлено: 01 июл 2007, 12:34
ARM
Да нет, не правильно, join то левый! Т.е. все записи из Users, и только те из Лога, кот. есть в Users.
Добавлено: 01 июл 2007, 17:47
mdfv
По моему вы перемудрили, результат правильный выдан.
вместо
напишите
суть не изменится, а смысл появится.
Re: Странная проблема с left join
Добавлено: 01 июл 2007, 20:38
WildSery
ARM писал(а):Может я не произнес какое-то заклинание ? В MS SQL отрабатывает на ура...
Чего врёшь-то? Не наговаривай на MSSQL такое.
Любой джойн выводит количество строк по одному условию, равное произведению числа строк в первой и второй, либо одну, в случае отсутствия и внешнего соединения.
Загляни, пожалуй, в Грабера Мартина, почитай про соединения.
Re: Странная проблема с left join
Добавлено: 02 июл 2007, 12:56
ARM
Спасибо, консерваторию подправил, век живи - век учись.
Помоги, плиз, еще с одной проблемой: есть все та же таблица пользователей (Users) и логирования (Log_UserSession). В пользователях поле UserId, в логировании - UserId (foreign key с Users.UserId), DateLogin, DateLogoff.
Нужно выбрать всех пользователей, а также дату последнего логирования (DateLogin) пользователя с условием, что пользователь еще не отключился (DateLogoff=null). Записей c DateLogoff=null может быть много (клиент отвалился по ошибке), поэтому нужно взять самую позднюю дату логирования + DateLogoff=null!!!
Я это вижу так:
select
U.UserId,
US.DateLogin
from Users U
left join
(
select
first 1
DateLogin
from Log_UserSession US
where DateLogoff is null and US.UserId = U.UserId
order by DateLogin desc
) as US(DateLogin)
НО поля внешней (в соединении) таблицы в подзапросе использовать нельзя, т.е.:
where DateLogoff is null and US.UserId = U.UserId
выделенное не пройдет.
За ранее спасибо.
Добавлено: 02 июл 2007, 13:26
mdfv
Дык так и можно.
Код: Выделить всё
select
U.UserId,
(
select
first 1
DateLogin
from Log_UserSession US
where DateLogoff is null and US.UserId = U.UserId
order by DateLogin desc
) as DateLogin
from Users U
Добавлено: 02 июл 2007, 13:30
ARM
mdfv писал(а):Дык так и можно.
Код: Выделить всё
select
U.UserId,
(
select
first 1
DateLogin
from Log_UserSession US
where DateLogoff is null and US.UserId = U.UserId
order by DateLogin desc
) as DateLogin
from Users U
Как вариант "только для выборки даты логирования" пойдет, НО вместе с датой логирования нужно выбрать другие данные из табл. логирования (надо было мне упомянуть), т.е. нужно рулить все таки в сторону подзапроса...
Добавлено: 02 июл 2007, 14:49
WildSery
Подзапросом можно, но это будет некрасиво и серверу опять же в напряг.
Сделай лучше хранимой процедурой.
Код: Выделить всё
for select UserID from Users into UserId
do begin
DateLogin = null;
select first 1 DateLogin
from Log_UserSession
where DateLogoff is null and UserId = :UserId
order by DateLogin desc
into DateLogin;
suspend;
end
Добавлено: 02 июл 2007, 14:54
ARM
WildSery писал(а):Подзапросом можно, но это будет некрасиво и серверу опять же в напряг.
Сделай лучше хранимой процедурой.
Код: Выделить всё
for select UserID from Users into UserId
do begin
DateLogin = null;
select first 1 DateLogin
from Log_UserSession
where DateLogoff is null and UserId = :UserId
order by DateLogin desc
into DateLogin;
suspend;
end
Спасибо, то что нужно.
А слона то я и не заметил...
