1

例如,假设我们正在进行一项研究,学生最多可以参加 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" 匹配用户名的条件。

4

1 回答 1

2

假设这Username在每个表中都是唯一的,那么您的第二个查询将是我首先尝试的方式,只需对删除distinct和简单地使用union(这意味着不同)而不是进行轻微修改union all

select *
from (
        select Username from t1
        union
        select Username from t2
        union
        -- ...
        select Username from t10
    ) distinct_usernames
    left join t1 on t1.Username = distinct_usernames.Username
    left join t2 on t2.Username = distinct_usernames.Username
    -- ...
    left join t10 on t10.Username = distinct_usernames.Username

从那里我会确保 Username 被索引,甚至可能将它用作clustered index。过去,我通过distinct_usernames在 proc 开始时将您的临时表(可能是索引或索引视图)实现为优化运气,但只有测试才能确定这是否值得。

完整的外部连接需要一堆or条件或coalesce参数,尽管它可能值得在几个表上尝试一下,看看性能是否存在。我无法猜测您的查询引擎最喜欢什么。

sys.columns此外,可以通过查询或information_schema.columns使用动态 SQL将查询构建为字符串然后执行它来获取您想要的列名。

于 2013-02-25T20:21:35.590 回答