Not in с переменной не работает в предложении where …. переменная — это запрос выбора

#sql #sql-server #tsql #subquery #where-clause

#sql #sql-сервер #tsql #подзапрос #where-предложение

Вопрос:

Я пытаюсь выяснить, что не так с моим запросом, потому что он не исключает строку, которую я хочу исключить в предложении not in . Я действительно ценю любые предложения. Заранее благодарю вас

У меня есть две таблицы

 TableOne
 
Id     Name         isHealthy
1      Apple           Y
2      Banana          Y
3      Grapes          Y
4      Guava           Y
5      Orange          Y
  

TableX

 Id     VALUE          isActive     DESCRIPTION
1      Apple,Banana       1        FRUITS
2      Orange             0        FRUITS
3      Grapes,Guava       1        FRUITS
  

Я хочу исключить в tableOne строках все имя столбца значение TableX

 DECLARE @EXCLUDEVAL VARCHAR(max) = (SELECT ''''
            Replace( String_agg([value], ','), ',', ''',''')
            '''' AS EXCLUDEVAL
   FROM   tablex
   WHERE  [description] = 'FRUITS'
          AND isactive = '1');

SELECT *
FROM   tableone
WHERE  NAME NOT IN ( @EXCLUDEVAL ); 
  

Я сделал этот запрос, однако он не исключает @EXCLUDEVAL , что вернет это значение

 'Apple','Banana','Grapes','Guava' 
  

Если я введу точное значение без использования переменной @EXCLUDEVAL в запросе, оно будет работать и исключаться, но я не хочу жестко кодировать, я хочу использовать переменную @EXCLUDEVAL в предложении where, но я не уверен, где я ошибаюсь.

Ответ №1:

Вы смешиваете статический и динамический SQL, что не работает.

Вы также следуете плохому дизайну базы данных, сохраняя несколько значений в одной строке и используя запятую для их разделения. Целью реляционной базы данных является сохранение одного значения для каждой строки / столбца. Если вы сможете это изменить, это значительно облегчит вашу жизнь в будущем.

Предполагая, что вы можете использовать полную статическую версию:

 SELECT *
FROM tableone
WHERE [NAME] NOT IN (
    SELECT [value]
    FROM tablex
    WHERE [description] = 'FRUITS'
    AND isactive = '1'
);
  

Однако, если вы не можете изменить дизайн и используете совместимость с базой данных 130 или лучше, вы можете использовать STRING_SPLIT with CROSS APPLY для достижения того, чего вы хотите.

 SELECT *
FROM tableone
WHERE [NAME] NOT IN (
    SELECT R.Result
    FROM tablex X
    CROSS APPLY (
        SELECT [value] Result
        FROM STRING_SPLIT(X.[VALUE],',')
    ) R
    WHERE [description] = 'FRUITS'
    AND isactive = '1'
);
  

Или, если вы используете более старую совместимость, вам необходимо реализовать собственную функцию разделения строк, которых много доступно с помощью быстрого поиска в Google, а затем CROSS APPLY снова:

 SELECT *
FROM tableone
WHERE [NAME] NOT IN (
    SELECT R.Result
    FROM tablex X
    CROSS APPLY dbo.MyStringSplitFunction(X.[Value],',') R
    WHERE [description] = 'FRUITS'
    AND isactive = '1'
);
  

Комментарии:

1. если используется это, столбец значений tablex получает запятую, он также не будет исключен в tableOne

2. @ShayneDavid вам нужно хранить свои данные с запятыми? Это определенно плохая практика…

3. Я ценю вашу помощь, на самом деле не нужно хранить через запятую, можно сделать, как хранить через запятую или в кавычках с запятой в качестве разделителя, я все еще учусь, я вроде как не уверен, какой подход лучше

4. Для хорошего проектирования базы данных у вас должна быть 1 строка на запись, не храните несколько значений в одной строке.

5. @ShayneDavid как у вас дела?