如何将嵌套查询放入 JOIN 中?

How to put nested query in a JOIN?

假设我有以下两个表:

表 1

+-------+-------+-------+
| data1 | data2 | data3 |
+-------+-------+-------+
|     1 |    12 |    13 |
|     2 |    22 |    23 |
|     3 |    32 |    33 |
+-------+-------+-------+

表 2

+-------+-------+-------+
| data1 | data4 | data5 |
+-------+-------+-------+
|     1 |  NULL |   015 |
|     1 |    14 |   115 |
|     1 |    14 |   115 |
|     2 |  NULL |   025 |
|     2 |    24 |   125 |
|     2 |    24 |   125 |
|     3 |  NULL |   035 |
|     3 |    34 |   135 |
|     3 |    34 |   135 |
+-------+-------+-------+

我有以下查询:

SELECT TABLE1.data1,
       TABLE1.data2,
       TABLE1.data3,
       (SELECT TOP 1
               data4
        FROM TABLE2
        WHERE data1 = TABLE1.data1
          AND data4 IS NOT NULL),
       (SELECT TOP 1
               data5
        FROM TABLE2
        WHERE data1 = TABLE1.data1
          AND data4 IS NOT NULL)
FROM TABLE1;

查询结果

+-------+-------+-------+-------+-------+
| data1 | data2 | data3 | data4 | data5 |
+-------+-------+-------+-------+-------+
|     1 |    12 |    13 |    14 |   115 |
|     2 |    22 |    23 |    24 |   125 |
|     3 |    32 |    33 |    34 |   135 |
+-------+-------+-------+-------+-------+

假设TABLE2满足这两个条件:

  1. 对于每个数据 1,数据 4 可以是 1 或在每一行中具有相同的值。
  2. 对于每个 data1,data5 将为 data4 为 null 的每一行提供一个值,为 data4 不为 null 的每一行提供另一个值。

有没有办法重写查询,使 select 部分没有嵌套查询?也许使用 JOIN 语句?我问是因为我意识到 SELECT 中嵌套查询的性能很差。但是,如果我尝试使用 JOIN,我最终会复制 data4 不同于 null 的行。

我注意到在您的 table2 中,除了 data4 中的 NULL,行没有区别。所以 SELECT DISTINCT 很容易编码,而且,尽管是资源密集型的,因为它是 GROUP BY *,本质上,对于这个例子来说已经足够好了。如果你有差异,结果表会突然出现你没有预料到的重复,这将指导你进一步的数据调查。

也就是说,给你:

WITH                                                                                                                                                                                                
-- your input ..
tb1(data1,data2,data3) AS (
          SELECT 1,12,13
UNION ALL SELECT 2,22,23
UNION ALL SELECT 3,32,33
)
,
tb2(data1,data4,data5) AS (
          SELECT 1,NULL,015
UNION ALL SELECT 1,14,115
UNION ALL SELECT 1,14,115
UNION ALL SELECT 2,NULL,025
UNION ALL SELECT 2,24,125
UNION ALL SELECT 2,24,125
UNION ALL SELECT 3,NULL,035
UNION ALL SELECT 3,34,135
UNION ALL SELECT 3,34,135
)
-- end of your input.
-- Real Query starts here; replace following comma with "WITH" ..
,
tb2grp AS (
  SELECT DISTINCT
    *
  FROM tb2
  WHERE data4 IS NOT NULL
  -- chk  data1 | data4 | data5 
  -- chk -------+-------+-------
  -- chk      1 |    14 |   115
  -- chk      2 |    24 |   125
  -- chk      3 |    34 |   135
)
SELECT
  tb1.data1
, tb1.data2
, tb1.data3
, tb2.data4
, tb2.data5
FROM tb1 JOIN tb2grp AS tb2 USING(data1)
ORDER BY data1;
-- out  data1 | data2 | data3 | data4 | data5 
-- out -------+-------+-------+-------+-------
-- out      1 |    12 |    13 |    14 |   115
-- out      2 |    22 |    23 |    24 |   125
-- out      3 |    32 |    33 |    34 |   135

您可以使用 OUTER APPLYCROSS APPLY

SELECT TABLE1.data1,
       TABLE1.data2,
       TABLE1.data3,
       t2.data4,
       t2.data5
FROM TABLE1
OUTER APPLY (SELECT TOP 1
               data4,
               data5
        FROM TABLE2 t2
        WHERE t2.data1 = TABLE1.data1
          AND t2.data4 IS NOT NULL
        ORDER BY t2.SomeColumn
-- TOP should have an ORDER BY otherwise results are not guaranteed
) t2;