SQL: Как отслеживать строки, которые уже сопоставлены в коррелированном подзапросе? - PullRequest
4 голосов
/ 14 сентября 2009

Вот еще один вызов для вас, SQL-гуру ...

Я написал здесь еще один вопрос о сопоставлении двух наборов результатов ( Как сопоставить / сравнить значения в двух наборах результатов в SQL Server 2008? ). Этот вопрос является продолжением этого вопроса и ответа, но так как это другая тема, я создаю его как новый вопрос.

Quassnoi предлагает следующее решение для выбора всех пользователей, которые соответствуют навыкам, необходимым для данного проекта:

SELECT * 
FROM   Users u  
WHERE  NOT EXISTS 
 ( 
 SELECT  NULL  
 FROM    ProjectSkill ps        
 WHERE   ps.pk_project = @someid               
 AND NOT EXISTS  
  (                
  SELECT  NULL                
  FROM    UserSkills us                
  WHERE   us.fk_user = u.id                        
          AND us.fk_skill = ps.fk_skill               
   )        
 )

Это прекрасно работает. Но что, если я хочу создать один запрос, в котором перечислены все проекты определенного дня, включая их наиболее подходящего пользователя. Я представляю себе следующий формат:

projectid        userid
----------       -----------
1                1234
2                5678
3                4321
4                8765

Важно, что пользователю предлагается только один раз в списке! ... потому что проекты находятся в один и тот же день, и пользователи не должны бронироваться дважды.

Теперь я могу представить себе некоторый SQL, например:

SELECT p.id 'projectid', ( SELECT TOP 1 u.id 
        FROM   Users u  
        WHERE  NOT EXISTS 
        ( 
             SELECT  NULL  
             FROM    ProjectSkill ps        
             WHERE   ps.pk_project = p.id 
             AND NOT EXISTS  
                 (                
          SELECT  NULL                
          FROM    UserSkills us                
          WHERE   us.fk_user = u.id                        
                 AND us.fk_skill = ps.fk_skill               
         )        
         )
         ORDER BY rating DESC
      ) 'userid'
FROM Projects p 
WHERE startdate > @beginningofday 
      AND startdate < @endofday

Но это (очевидно) радостно предлагает одного и того же пользователя снова и снова, если у него есть необходимые навыки для проектов.

Есть ли у кого-нибудь предложения о том, как отслеживать, какие строки в таблице Users уже совпадают ранее в запросе? Может быть, использование переменной? Или есть другой умный способ обойти это, что мне не хватает?

Запрос должен выполняться на SQL Server 2008.

Любая помощь будет принята с благодарностью! Спасибо.

С уважением Alex

Ответы [ 3 ]

1 голос
/ 15 сентября 2009

Ваша задача является классическим примером проблемы ладей .

Это не может быть эффективно решено в SQL.

Существуют некоторые простые алгоритмы, которые хорошо работают, если ваши работники, вероятно, будут обладать необходимыми навыками (т.е. неквалифицированный работник является скорее редким исключением, чем правилом).

Однако лучше использовать SQL, чтобы получить ограничения, т.е. е. какие пользователи подходят (или не подходят) к каким проектам и вводят их в эвристический алгоритм.

0 голосов
/ 15 сентября 2009

В нем содержатся оттенки проблемы коммивояжера - как оптимально подогнать N пользователей к X проектам (особенно, если вы ищете лучшего / наиболее подходящего пользователя для каждого проекта). При достаточно больших значениях N и X проблема может стать интрацибельной (т. Е. Вы не решите ее при жизни).

По общему признанию, это будет крайний случай. Тем не менее, я мог видеть, как растут требования, когда вы пытаетесь добавить все больше и больше функций в процесс. Я хочу сказать, что проблема, которую вы пытаетесь решить, не может быть разумно решаемой в T-SQL, не говоря уже об одном запросе. Создание списка рекомендуемых пользователей для каждого проекта и предоставление возможности принять окончательное решение может быть целесообразным здесь.

0 голосов
/ 14 сентября 2009

Это было давно, но я на самом деле думаю, что курсор (я ненавижу курсоры, они обычно используются неправильно) может помочь здесь.

Еще одна вещь, которую вы могли бы рассмотреть, это то, что пользователь должен быть забронирован на один день. Таким образом, «предложенный пользователь» может появиться в нескольких проектах, так как ничто еще не является окончательным. Кроме того, я бы предложил более одного пользователя для проекта, чтобы человек, назначающий их, мог выбрать то, что имеет смысл.

Кроме того, на самом деле бронирование пользователя в проекте может также устранить некоторую путаницу в будущем. Если пользователь меняет свои навыки, результаты запроса могут измениться.

Если у вас есть назначенный б / у, ваши прецеденты становятся намного понятнее

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...