如何在SQL中使用IN子句为不匹配的元素取回NULL

时间:2018-09-06 18:03:53

标签: sql sql-server sql-server-2000

SELECT 
  ColAlphaNum, 
  ColId 
FROM SomeTable 
WHERE ColAlphaNum IN ('01AAA','02BBB','03CCC','04DDD')

该表包含值01AAA,02BBB的记录。 sql返回以下结果集(我只需要查询“ SomeTable”表中的数据

 ColAlphaNum | ColId
 ------------+------
 01AAA       | 5
 02BBB       | 3

我想将不匹配的记录值返回为NULL,如下所示,但无法使其正常工作。

预期输出:

ColAlphaNum | total
------------+------
01AAA       | 5
02BBB       | 3
03CCC       | NULL
04DDD       | NULL

我试图通过case语句实现相同的目的,但是无法使其正常工作。尝试了此建议的解决方案Here可行,但是由于我必须从json列表中创建逗号分隔的ColAlphaNum值列表,并在上面的select语句中使用它们,所以union all选项可能很麻烦。有没有其他方法可以实现这一目标。

感谢您的帮助。

3 个答案:

答案 0 :(得分:2)

使用类似LEFT JOIN的方法从列表中构建表(在SQL 2000中应该可用):

SELECT List.ListItem, SomeTable.ColId
FROM (
    SELECT '01AAA' UNION
    SELECT '02BBB' UNION
    SELECT '03CCC' UNION
    SELECT '04DDD'
) AS List(ListItem)
LEFT JOIN SomeTable ON List.ListItem = SomeTable.ColAlphaNum

答案 1 :(得分:1)

如果IN (...)子句中有大量项目,则可能更好,更有效的方法是创建一个临时表来保存匹配项。

此示例代码无法在SQL Server 2000上运行,因为它依赖于使用SQL Server 2000中不提供的功能创建的示例数据。话虽如此,您无需在实际系统上创建示例数据,因此这应该不是问题。另外,为什么要使用SQL SERVER 2000?那是将近20年的代码,并且完全不受Microsoft支持。一个人不禁想到安全隐患。

创建临时表:

IF OBJECT_ID(N'tempdb...#Matches', N'U') IS NOT NULL
DROP TABLE #Matches;
CREATE TABLE #Matches
(
    AlphaNum char(5) NOT NULL
        CONSTRAINT Matches_pk
        PRIMARY KEY
        CLUSTERED
);

向其中插入100行测试数据(这不会在SQL Server 2000上运行):

INSERT INTO #Matches (AlphaNum)
SELECT TOP(100) 
    RIGHT('00' + CONVERT(varchar(2)
        , ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1  ), 2)
    + CHAR((CRYPT_GEN_RANDOM(1) & 25) + 65)
    + CHAR((CRYPT_GEN_RANDOM(1) & 25) + 65)
    + CHAR((CRYPT_GEN_RANDOM(1) & 25) + 65)
FROM sys.syscolumns c1;

临时表中10行的内容:

SELECT TOP(10) *
FROM #Matches;
╔══════════╗
║ AlphaNum ║
╠══════════╣
║ 00BQY    ║
║ 01RZJ    ║
║ 02YQB    ║
║ 03JAY    ║
║ 04QJB    ║
║ 05QIB    ║
║ 06ZYY    ║
║ 07QBJ    ║
║ 08ZAI    ║
║ 09QBA    ║
╚══════════╝

根据您的问题创建SomeTable,并用10,000行填充它:

IF OBJECT_ID('dbo.SomeTable', N'U') IS NOT NULL
DROP TABLE dbo.SomeTable;
CREATE TABLE dbo.SomeTable
(
    SomeTableID int NOT NULL IDENTITY(1,1)
        CONSTRAINT SomeTable_pk
        PRIMARY KEY
        CLUSTERED
    , AlphaNum char(5) NOT NULL
    , SomeCol varchar(500) NOT NULL
);

插入一些测试数据(同样,此部分将无法在SQL Server 2000上运行):

INSERT INTO dbo.SomeTable (AlphaNum, SomeCol)
SELECT TOP(10000) 
    AlphaNum = RIGHT('00' + CONVERT(varchar(2)
               , (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1) % 99)
               , 2)
        + CHAR((CRYPT_GEN_RANDOM(1) & 25) + 65)
        + CHAR((CRYPT_GEN_RANDOM(1) & 25) + 65)
        + CHAR((CRYPT_GEN_RANDOM(1) & 25) + 65)
    , SomeCol = CONVERT(varchar(1000), CRYPT_GEN_RANDOM(500))
FROM sys.syscolumns c1
    CROSS JOIN sys.syscolumns c2;

创建支持的非聚集索引:

CREATE NONCLUSTERED INDEX SomeTable_AlphaNum
ON dbo.SomeTable (AlphaNum)
INCLUDE (SomeCol); --INCLUDE clause does not work on SQL Server 2000, ignore it.

显示临时表中的所有行,以及临时表中与SomeTable中不匹配的行中NULLSomeTable的值相匹配(这肯定有效在SQL Server 2000上!):

SELECT m.AlphaNum
    , st.SomeCol
FROM #Matches m
    LEFT JOIN dbo.SomeTable st ON m.AlphaNum = st.AlphaNum;

该输出的前20行:

╔══════════╦══════════════════════╗
║ AlphaNum ║       SomeCol        ║
╠══════════╬══════════════════════╣
║ 00BQY    ║ NULL                 ║
║ 01RZJ    ║ NULL                 ║
║ 02YQB    ║ NULL                 ║
║ 03JAY    ║ NULL                 ║
║ 04QJB    ║ NULL                 ║
║ 05QIB    ║ NULL                 ║
║ 06ZYY    ║ NULL                 ║
║ 07QBJ    ║ SR{m‘x ™¨Hó‹µäôÅPÓ   ║
║ 08ZAI    ║ NULL                 ║
║ 09QBA    ║ NULL                 ║
║ 10RQA    ║ NULL                 ║
║ 11IAZ    ║ NULL                 ║
║ 12RZI    ║ NULL                 ║
║ 13ZRA    ║ NULL                 ║
║ 14IAI    ║ NULL                 ║
║ 15BIZ    ║ NULL                 ║
║ 16JBI    ║ NULL                 ║
║ 17AYJ    ║ Å N©U…C4Mòº³5ö„iÅ    ║
║ 18ZJI    ║ NULL                 ║
║ 19YRI    ║ NULL                 ║
╚══════════╩══════════════════════╝

答案 2 :(得分:0)

您可以使用values构造并执行left join

select t.ColAlphaNum, s.ColId as total
from ( values ('01AAA'),('02BBB'),('03CCC'),('04DDD') 
     ) t(ColAlphaNum) left join
     SomeTable s
     on s.ColAlphaNum = t.ColAlphaNum;