Как вы пишете недиманный SQLQuery только для того, чтобы возвращать записи, которые удовлетворяют нескольким предложениям EXISTS? - PullRequest
0 голосов
/ 29 мая 2019

Вот проблема, с которой я сталкиваюсь.У меня есть запрос (который работает), и я хочу, чтобы он возвращал только записи, в которых у пользователя есть записи для каждого предложения EXISTS.Например:

select * from Users
WHERE EXISTS (SELECT *
                FROM UserSessions
                WHERE UserSessions.UserId = Users.Id
                AND SessionId = 1)
        AND EXISTS (SELECT *
                FROM UserSessions
                WHERE UserSessions.UserId = Users.Id
                AND SessionId = 2)
        AND EXISTS (SELECT *
                FROM UserSessions
                WHERE UserSessions.UserId = Users.Id
                AND SessionId = 3)

Так что в конкретном случае я хочу, чтобы только пользователи имели идентификатор сеанса 1 И, идентификатор сеанса 2 И и идентификатор сеанса 3. Этот запрос работает, но изменение идентификатора сеансаи может быть 1 или 20 различных идентификаторов.

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

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

Ответы [ 2 ]

4 голосов
/ 29 мая 2019

Сначала создайте таблицу типа:

CREATE TYPE dbo.Ints AS TABLE(ID int PRIMARY KEY);
GO

Вы можете сделать это в качестве аргумента для вашей хранимой процедуры (и настроить свой код на стороне сервера для передачи в DataTable или List в качестве комплексного параметра, предполагая, что C # или тому подобное):

CREATE PROCEDURE dbo.GetSessionsThatMatchAllIDs
  @IDs dbo.Ints READONLY
AS
...

А пока просто для тестирования давайте заполним его вручную:

DECLARE @IDs dbo.Ints;
INSERT @IDs VALUES(1),(2),(3); -- ...,(20)

DECLARE @min = COUNT(*) FROM @IDs;

SELECT Id, ... 
  FROM dbo.Users AS u
  WHERE
  (
    SELECT COUNT(DISTINCT SessionID) 
      FROM dbo.UserSessions 
      WHERE UserID = u.ID 
      AND SessionID IN (SELECT ID from @IDs)
  ) = @min;
0 голосов
/ 29 мая 2019

Кажется разумным предположение, что ключи уникальны в таблице соединений / ассоциаций, такой как UserSessions.

Вы можете упростить логику до:

select u.*
from Users u join
     (select us.UserId
      from UserSessions us
      where SessionId in (1, 2, 3)   -- your list here
      group by us.UserId
      having count(*) = 3            -- size of the list
     ) us
     on us.UserId = u.Id;

Вы можетеДалее параметризуйте это, в зависимости от того, как вы хотите передать в свой список.Одним из методов будет синтаксический анализ строки:

with input_sessions as (
      select value as SessionId
      from string_split(@sessions_list, ',')
     )
    select u.*
    from Users u join
         (select us.UserId
          from UserSessions us
          where SessionId in (select sessionId from input_sessions)  
          group by us.UserId
          having count(*) = (select count*) from input_sessions)            
         ) us
         on us.UserId = u.Id;

Если ключи не уникальны, запросы могут быть настроены с учетом этого.

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