Как вернуть NULL для элементов, которые не совпадают, используя предложение IN в SQL - PullRequest
0 голосов
/ 06 сентября 2018
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

Я пытался добиться того же с заявлениями по делу, но не смог заставить его работать. Попробовал это предлагаемое решение Здесь это работает, но, поскольку мне нужно создать список значений ColAlphaNum, разделенных запятыми, из списка json и использовать их в приведенном выше операторе select, опция union all может быть громоздкой. Есть ли способ достичь этого другими способами.

Спасибо за вашу помощь.

Ответы [ 3 ]

0 голосов
/ 06 сентября 2018

Создайте таблицу из списка, используя что-то вроде и 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
0 голосов
/ 07 сентября 2018

Если в предложении 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 из своего вопроса и заполните его 10000 строками:

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 и NULL значений для строк в временной таблице, которые не совпадают в SomeTable (это ОПРЕДЕЛЕННО работает на 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                 ║
╚══════════╩══════════════════════╝
0 голосов
/ 06 сентября 2018

Вы можете использовать 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; 
...