#sql #tsql
#sql #tsql
Вопрос:
Таблица
Id || IdFrom || IdTo
--------------------------
1 || null || 2
2 || 1 || null
3 || null || 5
4 || null || 6
5 || 3 || 9
6 || 4 || 7
7 || 6 || null
8 || null || null
9 || 5 || 10
10 || 9 || null
947 || null || 949
949 || 947 || 952
950 || null || 951
951 || 950 || 952
952 || 951 || null
Необходимо получить все строки или только конкретные идентификаторы, которые находятся между всеми 3 столбцами при указании данного идентификатора. Итак, ВЫБЕРИТЕ (все идентификаторы, найденные в IdFrom или IDto, и эти IdFrom или IDto находятся в других IdFrom или IDto)
Результаты при поиске по идентификатору 1 выдадут результаты с идентификаторами 1 и 2
Результаты при поиске идентификатора 2 выдадут результаты с идентификаторами 1 и 2
Результаты при поиске по идентификатору 3,5,9 или 10 выдадут результаты с идентификаторами 3,5,9 и 10
Результаты при поиске идентификатора 4,6 или 7 выдадут результаты с идентификаторами 4,6 и 7
Мой текущий поиск представляет собой итерацию получения IdFrom и IDto для Id, помещения найденных идентификаторов в таблицу tmp и повторения поиска совпадений до тех пор, пока не будут найдены более четкие идентификаторы. Это работает, но крайне некрасиво и занимает больше времени, чем, вероятно, могло бы…
Наткнулся на запрос, который может получить все строки, которые имеют совпадение, но не указаны для определенного идентификатора
DECLARE @SearchForId int = 1
SELECT
t1.ID,t1.IdFROM,t1.IdTO
FROM SomeTable t1
WHERE
(
EXISTS(SELECT Id FROM SomeTable tblFROM WHERE tblFROM.IdFROM = t1.Id) OR
EXISTS(SELECT Id FROM SomeTable tblTO WHERE IdTO.IDTRANSFEREDTO = t1.Id)
)
AND Id = 1 <<-- this part just gives that id obvious but without it, it gets everything in the entire table
РЕДАКТИРОВАТЬ: добавлены новые идентификаторы (947-952). Предыдущее выбранное решение действительно предоставляло идентификаторы 947 и 949, но отсутствовало 950,951,952. Попытался добавить еще пару cte, подобных предыдущему решению, чтобы присвоить всем идентификаторам 947,949,950,951,952, но выдать только 947 и 949. Как получить все 5. Это решение было намного быстрее, почти в 25 раз. Хотелось бы сохранить его и получить идентификаторы остатка
Комментарии:
1. Вы могли бы попробовать и, по крайней мере, поделиться этим, даже если это не работает. В любом случае..
2. Извините за сделанную правку
Ответ №1:
Вам нужно сделать это, используя два рекурсивных общих табличных выражения.
declare @id int
set @id = 2
;WITH CTE1
AS(
SELECT c.*
FROM tbl c
WHERE c.Id = @id
UNION ALL
SELECT p.*
FROM CTE1 cte1_alias
INNER JOIN tbl p
ON p.IdFrom = cte1_alias.Id
),
CTE2
AS(
SELECT c.*
FROM tbl c
WHERE c.Id = @id
UNION ALL
SELECT p.*
FROM CTE2 cte2_alias
INNER JOIN tbl p
ON p.IdTo = cte2_alias.Id
)
SELECT Id FROM CTE1
Union
SELECT Id FROM CTE2
Комментарии:
1. Будет указан только 1 идентификатор. При поиске идентификатора 3 выдается 3,5,9 … или при поиске 5 выдается 3,5,9, или при поиске 9 выдается 3,5,9
2. похоже, пока это работает хорошо на 20 или около того столбцах, которые я пробовал. По какой-либо причине выполняется select * ?? Было бы лучше или быстрее просто выбрать необходимые столбцы в cte?
3. Вы можете упростить задачу, исключив столбцы, которые не используются в
joins
, однако, поскольку их слишком мало, это не будет иметь большого значения.4. Это сработало очень хорошо. После запуска с полной таблицей в ней отсутствовали некоторые идентификаторы. Смотрите редактирование, должно получиться 947,949,950,951,952, но получаем только 947 и 949
5. Отредактировал сообщение. Текущее решение хорошо работало для большинства. Необходимо получить другие идентификаторы, которые решение не нашло
Ответ №2:
Насколько я понимаю, было бы достаточно ИЛИ того, чтобы столбцы были равны заданному значению:
Declare @prm int = 1
Select Id
From SomeTable
Where Id=@prm Or IdFrom=@prm Or IdTo=@prm
или, для другого варианта, используйте in среди столбцов
Declare @prm int = 1
Select Id
From SomeTable
Where @prm in (Id, IdFrom, IdTo)