2014-02-19 2 views
0

На основе отличного решения, предоставленного Сергеем для моего вопроса C# здесь: Filter out path strings beginning with strings, я ушел, чтобы создать аналогичную вещь для T-SQL. Я могу реорганизовать это для использования в таблице памяти в отличие от курсоров, но мне очень хотелось бы посмотреть, есть ли подход на основе набора, который я могу предпринять для достижения той же цели.Оставьте только корневые пути в хранимой процедуре sql

Сценарий: У меня есть пути в db, например: C: \ Users, C: \ Users \ cheese, D: \ Shadow \ stuff, D: \ Shadow. Мне нужно фильтровать пути оставив только те rootmost (например, из выше 4, оставьте только C: \ Users, D: \ Shadow)

Это то, что я есть сейчас:

ALTER PROCEDURE [dbo].[GetPaths] 
@guy NVARCHAR(MAX) 
AS 
DECLARE 
@tempPath NVARCHAR(MAX) = '', 
@Path NVARCHAR (MAX), 
@filteredPath TABLE (FilteredPath NVARCHAR(MAX)) 
BEGIN 
    SET NOCOUNT ON; 
    IF (@guy IS NOT NULL) 
    BEGIN 
     DECLARE C Cursor FOR 
    SELECT Paths.Path 
      WHERE 
       Paths.Username = @guy 
      ORDER BY Paths.Path DESC 
      OPEN C 
       FETCH NEXT FROM C INTO @Path 
      WHILE @@Fetch_Status=0 BEGIN 
       IF (CHARINDEX(@tempPath, @Path = 0) 
       BEGIN 
       INSERT INTO @filteredPath(FilteredPath) 
         VALUES (@Path) 
       END 
       SET @tempPath = @Path 
       FETCH NEXT FROM C into @Path 
      END 
      CLOSE C 
      DEALLOCATE C 
       SELECT * FROM @filteredPath 
END 
END 
+0

Какую версию SQL Server вы используете ? –

+0

@GordonLinoff 2008 Express – zaitsman

+0

использование не использует функцию разделения отсюда, http: //stackoverflow.com/questions/2647/split-string-in-sql использовать dbo.fn_Split из ссылки – KumarHarsh

ответ

1

Обычно лучше делать что-то в базе данных как запрос select, а не использовать курсоры. Я считаю, что следующий будет эффективно использовать индекс на Paths(path):

select p.* 
from Paths p 
where not exists (select 1 
        from Paths p2 
        where p.path like p2.path + '%' and 
         p.path <> p2.path 
       ); 

(. К сожалению, я не могу проверить это сегодня)

Кстати, ваше выражение курсор отсутствует пункт from и это может имеют отношение к тому, почему это не работает.

+0

это потрясающе! Я бы поднял его два раза, если бы мог. Это примерно в два раза быстрее, чем решения, предлагаемые другими (на основе плана выполнения) и около 5% производительности того, что я придумал. Спасибо большое! – zaitsman

1

Вот мысль.

Если взять длину пути и вычесть длину пути с задними косыми чертами удалена, вы хотите только те, со значением 1. Что-то вроде этого:

SELECT Paths.Path 
FROM Paths 
WHERE Paths.Username = @guy 
     And Len(Path) - Len(Replace(Path, '\', '')) = 1 
ORDER BY Paths.Path DESC 

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

+0

Это работает (и это будет работать и для меня, так как я управляю входами). Спасибо за то, что вы взяли, чтобы ответить на мой вопрос. – zaitsman

1

Может ли вы не просто переписать в виде запроса с использованием CASE о дифференцироваться между этими путями на уровне «корней» и те, которые имеют подкаталоги:

SELECT DISTINCT 
     CASE (CHARINDEX('\', Path, CHARINDEX('\', Path) + 1)) 
      WHEN 0 THEN Path 
      ELSE SUBSTRING(Path, 1, (CHARINDEX('\', Path, CHARINDEX('\', Path) + 1) - 1)) 
     END 
    FROM Paths 
    WHERE Username = @guy 
+0

thats большой подход, не думал об этом. – zaitsman

Смежные вопросы