所以......这有点令人困惑。我有2个表,一个基本上是人员和主题的代码和名称列表,然后是一个值,例如:
第二个表只是一个主题列表,带有一个值和一个“结果”,它也只是一个数值:
现在,我要做的是在第一个表上执行LEFT OUTER JOIN
,匹配主题和值,以从第二个表中获取“结果”字段。这在大多数情况下都很简单,因为它们几乎总是完全匹配,但是在某些情况下会出现这种情况,在这种情况下问题是表1中的“值”低于所有情况表2中的值。在这种情况下,我想简单地执行JOIN,就好像表1中的值等于表2中该主题的最低值 。
要突出显示 - 如果我在主题和值上匹配,则LEFT OUTER JOIN
将不为第2行返回任何内容,因为表2中没有值为30的地理行。在这种情况下,我希望它只是选择值为35的行,然后在JOIN中返回Result字段。
这有意义吗?而且,有可能吗?
非常感谢。
答案 0 :(得分: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,即使它不是“有效”值(假设主题是有效值列表,但我不能从你的描述中说出来。)
从技术上讲,你只需要在select语句中使用case语句,而不是下面的mTopic.minValue,但我认为这个例子显示效果更好。
答案 1 :(得分: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。希望这可以帮助你
答案 2 :(得分:0)
执行此操作的另一种方法是使用临时表来保存不同的值。 首先插入完全匹配,然后插入初始选择中未找到的非精确匹配,最后从临时表中获取所有结果。这个解决方案比其他解决方案更多,所以只需添加它作为替代方案。
示例(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
答案 3 :(得分:0)
要求中未调用左连接。你想在T1.Subject = T2.Topic时加入,然后当T1.Value = T2.Value或T1.Value&lt;时加入。 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