例如,假设我们正在进行一项研究,学生最多可以参加 10 项不同的测试,并且数据库中的每个表都存储了所有学生对一项测试的回答。这些表在每个测试后命名为:T1、T2、...、T10。假设每个表都有一个标识每个学生的主键列“用户名”。学生可能完成了每项测试,也可能没有完成,因此每个学生的每个表中可能有也可能没有记录。
从所有表中返回所有测试数据的正确 SQL 查询是什么,每个学生一行(每个用户名一行)?我想要返回正确结果的最简单的查询。我还想在最终查询中将用户名字段合并为单个用户名字段。
澄清一下,我知道 SQL 有一个主要限制,因为它不支持选择所有列的语法,除了一个或多个字段,如“select *[^ExcludeColumn1][^ExcludeColumn2]”。为了避免在最终查询中专门命名所有列,可以将所有用户名列保留在那里,只要它在开头包含一个名为 RowID 的合并用户名字段。
至于整体查询,一个选项是对所有十个表的用户名列执行联合,然后在所有表中选择不同的用户名,然后对所有 10 个表上的不同用户名列表执行一系列左连接. 这将导致一个非常简单的查询,其中每个左连接都在同一组不同的用户名上执行,但我想避免对不同的用户名进行单独的预先查询。(尽管如果这是最好的选择,请告诉我)。它看起来像这样:
select * from
(select distinct coalesce(t1.Username,t2.Username,...,t10.Username) as RowID from t1,t2,t3,t4,t5,t6,t7,t8,t9,t10) distinct_usernames
left join t1 on t1.Username = distinct_usernames.RowID
left join t2 on t2.Username = distinct_usernames.RowID
...
left join t10 on t10.Username = distinct_usernames.RowID
尽管这很短且易于编写,但它的效率非常低,并且需要花费数小时才能在每个包含 5000 多行的测试表上运行,因此经过调整,在几秒钟内运行的等效版本是:
select * from (
select distinct Username as RowID from (
select Username from t1
union all
select Username from t2
union all
...
select Username from t10
) all_usernames) distinct_usernames
left join t1 on t1.Username = distinct_usernames.RowID
left join t2 on t2.Username = distinct_usernames.RowID
...
left join t10 on t10.Username = distinct_usernames.RowID
我认为我上面的查询可能是最有效和最正确的查询(只需几秒钟即可运行并返回正确的结果集),但我也认为也许可以通过某种完全连接来简化它。问题是完全连接会与两个以上的表混淆,因为如果没有预先确定用户名,每个后续表都必须将记录与前面的任何表进行匹配,导致查询中每个附加表都有“[previous table count] + 1" 匹配用户名的条件。