#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 как у вас дела?