У меня есть запрос, который я написал для SQL Server 2012, чтобы взять динамический список c сотрудников и определить, сколько времени они проводят каждый день в определенных областях. Когда я запускаю запрос от человека за раз, я получаю хорошие результаты. Однако, если я передам все параметры в предложении IN, то получу не только меньше результатов, но и некоторые значения, отличающиеся и просто неверные.
В конечном итоге это будет выполнено в отчете в SSRS, но даже если данные обрабатываются напрямую в SSMS, они демонстрируют то же поведение.
@People
- это отдельный запрос, который собирает список людей, которые действительно были в этом районе в тот день. @Yesterday
и @Today
являются просто переменными для дат.
SELECT *
FROM
(SELECT
AdmitType,
Time,
Person,
Door,
Direction,
CASE
WHEN Direction LIKE 'In' AND LEAD(Direction, 1) OVER(ORDER BY Time ASC) LIKE 'Out'
THEN DATEDIFF (second, Time, LEAD(Time, 1) OVER(ORDER BY Time ASC))
ELSE NULL
END AS 'Duration'
FROM
ActivityLog
WHERE
Door IN ('Room1', 'Room2', 'Room3')
AND Time BETWEEN @Yesterday AND @Today
AND Person IN @People) s1
ORDER BY
Person, Door, Time ASC
Если я выполню приведенный выше запрос и передам параметр @People
со значением ('Tom', 'Dick', 'Harry')
, я получу что-то подобное для записей Тома (исключая некоторые столбцы и несколько человек и двери для ясности):
Time Direction Duration
-----------------------------
7:12:04 IN 922
7:27:26 OUT NULL
8:40:37 IN NULL
9:07:04 OUT NULL
Но если я выполню запрос только с Томом, указанным в предложении IN, я получу следующее, что правильно:
Time Direction Duration
-----------------------------
7:12:04 IN 922
7:27:26 OUT NULL
8:40:37 IN 1587
9:07:04 OUT NULL
Как я могу исправить свой запрос, чтобы он возвращал правильную информацию для всех выбранных (обычно примерно 25 человек), или взять параметр и запустить каждого человека по одному и объединить результаты?
Я видел запрос, который пропускает список по одному и объединяет все результаты, но я не знаю, как написать это так, чтобы принимать входные параметры, которые будут переданы из SSRS.
Дополнительные данные добавлены по предложению Алана Шофилда: когда я добавил предложение PARTITION BY, я теперь получаю данные для этих предыдущих значений NULL, но это не соответствует прямые данные.
SELECT *
FROM
(SELECT
AdmitType,
Time,
Person,
Door,
Direction,
CASE
WHEN Direction LIKE 'In' AND LEAD(Direction, 1) OVER(PARTITION BY Person, Door ORDER BY Time ASC) LIKE 'Out'
THEN DATEDIFF (second, Time, LEAD(Time, 1) OVER(ORDER BY Time ASC))
ELSE NULL
END AS 'Duration'
FROM
ActivityLog
WHERE
Door IN ('Room1', 'Room2', 'Room3')
AND Time BETWEEN @Yesterday AND @Today
AND Person IN @People) s1
ORDER BY
Person, Door, Time ASC
Вот более крупный пример набора данных с результатами нового предложения PARTITION BY:
Time Person Door Direction Duration
18:07:22 John Room1 IN 1308 (Correct)
18:29:10 John Room1 Out NULL
17:42:18 John Room3 IN 1406 (Correct)
18:05:44 John Room3 Out NULL
7:12:04 Tom Room1 IN 922 (Correct)
7:27:26 Tom Room1 Out NULL
8:40:37 Tom Room1 IN 2 (Previously NULL, Now 2, should be 1587 and is when queried alone)
9:07:04 Tom Room1 Out NULL
9:09:07 Tom Room1 IN 31 (Previously NULL, Now 31, should be 1256 and is when queried alone)
9:30:03 Tom Room1 Out NULL
9:38:48 Tom Room1 IN 48 (Correct)
9:39:36 Tom Room1 Out NULL
9:39:45 Tom Room1 Out NULL
9:40:36 Tom Room1 IN 90 (Correct)
9:42:06 Tom Room1 Out NULL
10:25:0 Tom Room1 IN 47 (Previously 47, Now 47, Should be 8939 and is when queried alone)
12:54:08 Tom Room1 Out NULL
14:09:42 Tom Room1 IN 39 (Correct)
14:10:21 Tom Room1 Out NULL
14:39:03 Tom Room1 IN 1316 (Previously NULL, Now 1316, should be 4178 and is when queried alone)
15:48:41 Tom Room1 Out NULL
15:49:20 Tom Room1 IN 52 (Previously NULL, Now 52, should be 1542 and is when queried alone)
16:15:02 Tom Room1 Out NULL
16:22:26 Tom Room1 IN 292 (Previously 292, Now 292, should be 1504 and is when queried alone)
16:47:30 Tom Room1 Out NULL
Данные продолжаются намного дольше, но, надеюсь, это даст лучшую идею.