2015-01-23 3 views
1

Итак ... это немного запутанно. У меня есть 2 таблицы, один в основном перечень кодов и названий людей и тем и затем значение, например:LEFT OUTER JOIN ... с различными совпадающими ключами

enter image description here

Вторая таблица представляет собой список тем, с значением и «результат», который только численное значение тоже:

enter image description here

Теперь, что я хочу сделать, это сделать LEFT OUTER JOIN первой таблицы, соответствующие по теме и значение, чтобы получить поле «результат» вторая таблица. Это просто в большинстве случаев, потому что они почти всегда будут точным совпадением, однако некоторых случаев их не будет, и в этих случаях проблема будет заключаться в том, что «Значение» в таблице 1 ниже всех значения в таблице 2. в этом случае, я хотел бы просто инфу, как если бы значение в таблице 1 равнялось наименьшее значение для этой теме в таблице 2.

для изюминка - LEFT OUTER JOIN не вернет ничего для строки 2, если я совпадаю по теме и значению, потому что в таблице 2 нет значения географии со значением 30. В этом случае мне бы хотелось просто выбрать строку, где значение равно 35, и вернуть поле результата из там в JOIN.

Это имеет смысл? И, возможно ли это?

Большое значение.

+0

Существует не точное совпадение 'Mathematics', но в этом случае значение в' table1' не ниже, чем все значения в 'table2' ... что вы хотите сделать? –

+0

@DavidFaber Я испортил свой первый стол - они должны совпадать. Я отредактирую сообщение, извините за путаницу. –

+0

Есть темы, похожие на темы? – Strawberry

ответ

1

Вы можете использовать Cross Apply здесь. Там может быть лучшее решение.

declare @people table(
Code int, 
Name varchar(30), 
Topic varchar(30), 
Value int 
) 

declare @topics table(
[Subject] varchar(30), 
Value int, 
Result int 
) 

INSERT INTO @people values (1, 'Doe,John', 'History', 25), 
(2, 'Doe,John', 'Geography', 30), 
(3, 'Doe,John', 'Mathematics', 45), 
(4, 'Doe,John', 'Brad Pitt Studies', 100) 

INSERT INTO @topics values ('History', 25, 95), 
('History', 30, 84), 
('History', 35, 75), 
('Geography', 35, 51), 
('Geography', 40, 84), 
('Geography', 45, 65), 
('Mathematics', 45, 32), 
('Mathematics', 50, 38), 
('Mathematics', 55, 15), 
('Brad Pitt Studies', 100, 92), 
('Brad Pitt Studies', 90, 90) 

SELECT p.Code, p.Name, 
case when p.Value < mTopic.minValue THEN mTopic.minValue 
    else p.Value 
END, mTopic.minValue 
FROM @people p 
CROSS APPLY 
(
SELECT [Subject], 
    MIN(value) as minValue 
FROM @topics t 
WHERE p.Topic = t.Subject 
GROUP BY [Subject] 
) mTopic 

Я также предполагаю, что:

Это просто в большинстве случаев, потому что они почти всегда будет точным совпадением, однако там будут какие-то случаи, не будет, и в в этих случаях проблема будет заключаться в том, что «Значение» в таблице 1 ниже всех значений в таблице 2.

является правильным. Если есть время, когда значение не равно ни одному значению темы И не меньше минимального, оно в настоящее время возвращает значение people.value, даже если оно не является «допустимым» значением (при условии, что темы представляют собой список допустимых значений, но я не могу сказать по вашему описанию.)

Также технически вам нужен только оператор case в инструкции select, а не следующий mTopic.minValue, но я думал, что пример показал эффект лучше с ним.

+0

Hi @ david-jacobsen Извинения за глупые изменения, видимо, мне не разрешено нажать клавишу возврата -_-. В любом случае ... Я смущен, насколько это точно работает ... как CASE и CROSS APPLY работают вместе, так что, если, например, мы рассматриваем строку «География» в Таблице 1, CASE проверяет минимальное значение для группы «География», созданной CROSS APPLY? ИЗМЕНИТЬ СНОВА: Ничего, я идиот, это говорит, что это просто как день в вашем примере. Спасибо, я попробую. –

+0

Mr @ david-jacobsen, вы джентльмен и ученый. Это больно моему мозгу, но, похоже, работает отлично, большое спасибо. –

+0

Я просто хотел ответить на ваш комментарий, что я боялся, что это не сработает. В моей хромированной вкладке сказано, что это MySQL - LEFT OUTER JOIN ... и я не верю, что MySQL имеет перекрестный подход! Я рад, что это сработало для вас. Короче говоря, это кросс-подход позволяет использовать поля из левой таблицы в запросе с правой стороны, что дает нам минимальное значение. –

0

В этом случае я бы сделал два объединения вместо одного. Что-то вроде этого:

select * 
from Table1 T1 
LEFT JOIN Table2 T2 on T1.Topic=T2.subject and T1.Value=T2.VALUE 
LEFT JOIN Table2 as T3 on T1.Topic=T3.Subject and T1.Value<T2.Value 

Делайте случай, чтобы выбрать таблицу для принятия значений. Если значение T2.value равно null, используйте T3.Value ELSE T2.Value. Надеюсь, это поможет вам

0

Другой способ выполнения этого - использование временной таблицы для хранения различных значений. Сначала вставьте точные совпадения, затем вставьте точные совпадения, которые не найдены в первоначальном выборе и, наконец, возьмите все результаты из таблицы temp. Это решение больше кода, чем другое, поэтому просто добавьте его в качестве альтернативы.

Пример (SqlFiddle):

Схема первого

create table students 
    (code  integer, 
     name  varchar(50), 
     topic varchar(50), 
     value integer); 

create table subjects 
    (subject varchar(50), 
     value varchar(50), 
     result integer); 

insert students 
    (code, name, topic, value) 
values 
    (1, 'Doe, John', 'History',   25), 
    (2, 'Doe, John', 'Geography',   30), 
    (3, 'Doe, Jane', 'Mathematics',  45), 
    (4, 'Doe, Jane', 'Brad Pitt Studies', 100); 

insert subjects 
    (subject, value, result) 
values 
    ('History',   25, 95), 
    ('History',   30, 84), 
    ('History',   35, 75), 
    ('Geography',   35, 51), 
    ('Geography',   40, 84), 
    ('Geography',   45, 65), 
    ('Mathematics',  45, 32), 
    ('Mathematics',  50, 38), 
    ('Mathematics',  55, 15), 
    ('Brad Pitt Studies', 100, 92), 
    ('Brad Pitt Studies', 90, 90); 

Фактический запрос SQL:

-- Temp table to hold our results 
create temporary table tempresult 
    (code   integer, 
     name   varchar(50), 
     topic  varchar(50), 
     studentvalue integer, 
     subjectvalue integer, 
     result  integer); 

-- Get the exact results 
insert tempresult 
    (code, 
     name, 
     topic, 
     studentvalue, 
     subjectvalue, 
     result) 
select stu.code, 
     stu.name, 
     stu.topic, 
     stu.value as 'student_value', 
     sub.value as 'subject_value', 
     sub.result 
    from students stu 
     join 
     subjects sub on sub.subject = stu.topic 
        and sub.value = stu.value; 

-- Get the non-exact results, excluding the 'students' that we already 
-- got in the first insert 
insert tempresult 
    (code, 
     name, 
     topic, 
     studentvalue, 
     subjectvalue, 
     result)  
select stu.code, 
     stu.name, 
     stu.topic, 
     stu.value as 'student_value', 
     sub.value as 'subject_value', 
     sub.result 
    from students stu 
     join 
     subjects sub on sub.subject = stu.topic 
         -- Business logic here: Take lowest subject value that is just above the student's value 
        and sub.value = (select min(sub2.value) 
             from subjects sub2 
             where sub2.subject = stu.topic 
             and sub2.value > stu.value) 
where not exists (select 1 
        from tempresult tmp 
        where tmp.code = stu.code 
         and tmp.name = stu.name 
         and tmp.topic = stu.topic) 

-- Get our resultset 
select code, 
     name, 
     topic, 
     studentvalue, 
     subjectvalue, 
     result 
    from tempresult 
order by code, 
      name, 
      topic, 
      studentvalue, 
      subjectvalue, 
      result 
0

Левый присоединиться не предусмотрено в требованиях. Вы хотите присоединиться, когда T1.Subject = T2.Topic, а затем либо когда T1.Value = T2.Value, либо когда T1.Value < T2.Value и T2.Value - это наименьшее значение. Просто напишите это именно так:

select p.*, t.Result 
from @People p 
join @Topics t 
    on t.Subject = p.Topic 
    and( t.Value  = p.Value 
     or( p.Value < t.value 
      and t.Value =(
      select Min(Value) 
      from @Topics 
      where Subject = t.Subject))); 

, который генерирует:

Code Name  Topic    Value Result 
---- -------- ----------------- ----- ------ 
1 Doe,John History   25 95 
2 Doe,John Geography   30 51 
3 Doe,John Mathematics  45 32 
4 Doe,John Brad Pitt Studies 100 92