使用 Left Join 时,如何显示区分空字符串值和不存在值的数据?

When Using Left Join, how do I present data differentiating between empty string-values and non-existing values?

我需要创建一个 table,其中包含来自不同数据库环境中不同 table 的列,并将它们与跨这些 table 的公共键匹配。其中许多值都有合理的理由为空,但在某些环境中它们甚至不存在,这是我需要确定的问题,可能通过插入自定义字符串,例如"\\NULL///"...

我有一组预生产环境,其中每个环境在 table 中都有很多配置参数,我已经将它们提取到一个巨大的 table.

我现在正在尝试编写一个 SQL 以在 2D-table 中呈现某些参数集(环境与参数 x-ref 值 table),以确定有问题的值,完全缺少一些参数。

SELECT x0.envName,
       x1.param1,
       x2.param2,
       x3.param3
FROM ( ( (
            (SELECT envName
             FROM paramTable
             GROUP BY envName) x0
          LEFT JOIN
            ( SELECT envName,
                     parameterValue AS param1
             FROM paramTable
             WHERE parameterName='param1' ) x1 ON x1.envName = x0.envName )
        LEFT JOIN
          ( SELECT envName,
                   parameterValue AS param2
           FROM paramTable
           WHERE parameterName='param2' ) x2 ON x2.envName = x0.envName )
      LEFT JOIN
        ( SELECT envName,
                 parameterValue AS param3
         FROM paramTable
         WHERE parameterName='param3' ) x3 ON x3.envName = x0.envName)

如果我的参数表是这样的:

+ paramTable
=================================================
envName         | paramName     | paramValue    |
-------------------------------------------------
env1            | param1        | abcdef        |
env1            | param2        | 123456        |
env1            | param3        | A73BB2        |
env2            | param1        | klmnop        |
env2            | param2        | 987654        |
env2            | param3        |               |
env3            | param2        | uvwxyz        |

然后,此查询的结果 table 将不会区分空字符串值(例如 env2 上的 param3)和不存在的值(例如 env3 中的 param1 和 param3):

+ ResultQueryResult
=================================================================
envName         | param1        | param2        | param3        |
-----------------------------------------------------------------
env1            | abcdef        | 123456        | A73BB2        |
env2            | klmnop        | 987654        |               |
env3            |               | uvwxyz        |               |

我想以某种方式修改 SQL,以便结果查询会得到这样的结果:

+ PreferedQueryResult
=================================================================
envName         | param1        | param2        | param3        |
-----------------------------------------------------------------
env1            | abcdef        | 123456        | A73BB2        |
env2            | klmnop        | 987654        |               |
env3            | <<<!NULL!>>>  | uvwxyz        | <<<!NULL!>>>  |

你可以简单地使用像 <<<!NULL!>>> 这样的特殊常量并更改:

select paramValue

来自

select nvl(paramValue,'<<<!NULL!>>>')

或添加一个布尔列(对于每个参数):

替换

select paramValue

来自

select
    case when paramValue is null
    then True
    else False
    end as isParamValueNull,
    paramValue

在结果中包含来自内部 table 的 NOT NULL 字段。然后,当该字段为 NULL 时,您知道内部行不存在(与其 NULL-able 字段为 NULL 相反)。

当在必须为 NOT NULL 的主键上加入时,您可以使用其中一个 PK 字段(在您的情况下似乎是 envName/paramName)。否则,你可以 "invent" 你自己的非 NULL 字段,通过在子查询上加入:

...
LEFT JOIN (SELECT 1 inner_exists, <other fields> FROM inner ...) Q
    ON ...

避免使用 "magic" 值,因为您永远不知道它们是否实际存在于真实数据中。或者,如果你走那条路,使用不太可能出现的东西,比如 GUID。

   DECLARE @paramTable TABLE (envName  varchar(15), parameterName varchar(15), parameterValue varchar(15) )
   INSERT INTO @paramTable (envName, parameterName, parameterValue)
   VALUES 
       ('env1','param1','abcdef') 
      ,('env1','param2','123456') 
      ,('env1','param3','A73BB2') 
      ,('env2','param1','klmnop') 
      ,('env2','param2','987654') 
      ,('env2','param3',''   )  
      ,('env3','param2','uvwxyz') 

   select x0.envName, ISNULL(x1.param1,'<<!NULL!>>') as param1, ISNULL(x2.param2,'<<!NULL!>>') as param2,ISNULL(x3.param3,'<<!NULL!>>') as param3
   from
   (
     (
       (
         (select envName from @paramTable group by envName) x0      
         left join
         (
           select envName, parameterValue as param1 from @paramTable where parameterName='param1'
         ) x1
         on x1.envName = x0.envName
       )

       left join
       (
         select envName, parameterValue as param2 from @paramTable where parameterName='param2'
       ) x2
       on x2.envName = x0.envName
     )

     left join (
       select envName, parameterValue as param3 from @paramTable where parameterName='param3'
     ) x3
     on x3.envName = x0.envName
   )

结果:

           envName         param1          param2          param3
    --------------- --------------- --------------- ---------------
    env1            abcdef          123456          A73BB2
    env2            klmnop          987654          
    env3            <<!NULL!>>      uvwxyz          <<!NULL!>>

我试图重写您的查询:

SELECT x0.envName,
       CASE WHEN x1.parameterName='param1' THEN x1.param1 ELSE '<<!NULL!>>' END AS param1,
       CASE WHEN x1.parameterName='param2' THEN x1.param1 ELSE '<<!NULL!>>' END AS param2,
       CASE WHEN x1.parameterName='param3' THEN x1.param1 ELSE '<<!NULL!>>' END AS param3
FROM (SELECT envName
      FROM paramTable
      GROUP BY envName) x0
        LEFT JOIN paramTable x1
            ON x1.envName = x0.envName