У нас есть таблица встреч, как показано ниже. Каждое назначение должно быть отнесено к категории «Новое» или «Последующее наблюдение». Любое посещение (для пациента) в течение 30 дней после первого посещения (для этого пациента) является последующим наблюдением. Через 30 дней назначение снова «Новое». Любая встреча в течение 30 дней становится «продолжением».
В настоящее время я делаю это, набирая цикл while.
Как этого добиться без цикла WHILE?
Таблица
CREATE TABLE #Appt1 (ApptID INT, PatientID INT, ApptDate DATE)
INSERT INTO #Appt1
SELECT 1,101,'2020-01-05' UNION
SELECT 2,505,'2020-01-06' UNION
SELECT 3,505,'2020-01-10' UNION
SELECT 4,505,'2020-01-20' UNION
SELECT 5,101,'2020-01-25' UNION
SELECT 6,101,'2020-02-12' UNION
SELECT 7,101,'2020-02-20' UNION
SELECT 8,101,'2020-03-30' UNION
SELECT 9,303,'2020-01-28' UNION
SELECT 10,303,'2020-02-02'
fast_forward
курсору, вероятно, будет вашим лучшим вариантом, с точки зрения производительности.Ответы:
Вам нужно использовать рекурсивный запрос.
Период 30 дней отсчитывается, начиная с prev (и нет, это невозможно сделать без рекурсии / необычного обновления / цикла). Именно поэтому все существующие ответы с использованием только
ROW_NUMBER
не удалось.ДБ <> Fiddle Demo
Вывод:
Как это работает:
Подобный класс:
Условная сумма в Oracle - ограничение оконной функции
Окно сеанса (Azure Stream Analytics)
Запуск Итого, пока не выполнено определенное условие - Причудливое обновление
добавление
Никогда не используйте этот код на производстве!
Это можно сделать в «одиночном» раунде (причудливое обновление):
Запрос:
Обновление db <> fiddle Quirky
источник
RANGE x PRECEDING
предложение.Вы можете сделать это с помощью рекурсивного cte. Вы должны сначала заказать apptDate для каждого пациента. Это может быть достигнуто заурядным циклом.
Затем, в анкерной части вашего рекурсивного CTE, выберите первый заказ для каждого пациента, отметьте статус «новый», а также пометить apptDate как дату последнего «новый» рекорд.
В рекурсивной части вашего рекурсивного cte, приращения к следующему назначению, рассчитайте разницу в днях между текущим назначением и самой последней «новой» датой назначения. Если оно превышает 30 дней, отметьте его как «новое» и сбросьте самую последнюю новую дату встречи. В противном случае пометьте его как «отслеживание» и просто пройдите существующие дни с даты новой встречи.
Наконец, в базовом запросе просто выберите нужные столбцы.
Я должен упомянуть, что я сначала удалил этот ответ, потому что ответ Abhijeet Khandagale, казалось, отвечал вашим потребностям с помощью более простого запроса (после его доработки). Но с вашим комментарием к нему о ваших бизнес-требованиях и добавленными образцами данных я восстановил мои, потому что считаю, что это отвечает вашим потребностям.
источник
Я не уверен, что это именно то, что вы реализовали. Но другой вариант, о котором стоит упомянуть помимо использования cte, это использовать временную таблицу и обновлять ее в «раундах». Таким образом, мы собираемся обновить временную таблицу, пока все состояния не установлены правильно, и построить результат итеративным способом. Мы можем контролировать количество итераций, используя просто локальную переменную.
Таким образом, мы разделили каждую итерацию на два этапа.
Так
Обновить. Прочитайте комментарий, предоставленный Лукаш. Это намного умнее. Я оставляю свой ответ просто как идею.
источник
Я считаю, что рекурсивное общее выражение - отличный способ оптимизировать запросы, избегая циклов, но в некоторых случаях это может привести к снижению производительности, и его следует избегать, если это возможно.
Я использую приведенный ниже код, чтобы решить проблему и проверить ее на большее количество значений, но призываю вас также проверить ее на реальных данных.
Идея довольно проста - я хочу разделить записи в группе (30 дней), в какой группе самая маленькая запись
new
, а в остальныхfollow ups
. Проверьте, как построено утверждение:Так:
* 1.0 / 30
добавлено+ 0.000001
; Кроме того, мы используем функцию потолка, чтобы получитьsmallest integer greater than, or equal to, the specified numeric expression
Вот и все. Имея такую группу, мы просто используем ее,
ROW_NUMBER
чтобы найти дату начала и сделать ее такой,new
а остальные оставить какfollow ups
.источник
С уважением ко всем и в ИМХО
При использовании не так много прироста
Recursive CTE
иWindow Partition function
все в одном.Appid
должно бытьint identity(1,1)
, или это должно быть постоянно увеличиваетсяclustered index
.Помимо других преимуществ это также гарантирует, что все последующие ряды
APPDate
этого пациента должны быть больше.Таким образом, вы можете легко поиграть
APPID
в своем запросе, что будет более эффективно, чем помещатьinequality
операторы типа>, <в APPDate. Помещениеinequality
оператора как>, <в APPID поможет Sql Optimizer.Также в таблице должно быть два столбца даты
Так как это самые важные столбцы в самой важной таблице, поэтому не так много приведено.
Так
Non clustered index
может быть создано на AppdateПротестируйте мой скрипт с другими примерами данных и узнайте, для каких примеров он не работает. Даже если это не сработает, я уверен, что это можно исправить в самой логике моего скрипта.
источник
Хотя в вопросе этот вопрос четко не рассматривается, легко понять, что даты назначений нельзя просто классифицировать по 30-дневным группам. Это не имеет никакого делового смысла. И вы также не можете использовать идентификатор приложения. Сегодня можно назначить новую встречу для
2020-09-06
, Вот как я решаю эту проблему. Сначала получите первую встречу, затем вычислите разницу в дате между каждой встречей и первой квартирой. Если это 0, установите «Новый». Если <= 30, «Продолжение». Если> 30, установите значение «Не определено» и выполняйте проверку следующего раунда, пока не останется «Не определено». И для этого вам действительно нужен цикл while, но он не перебирает каждую дату встречи, а только несколько наборов данных. Я проверил план выполнения. Несмотря на то, что строк всего 10, стоимость запроса значительно ниже, чем при использовании рекурсивного CTE, но не так низка, как метод добавления Лукаша Шозды.источник
Я надеюсь, что это поможет вам.
источник
Вы могли бы использовать
Case
заявление .Вопрос в том, должна ли эта категория назначаться на основе первоначальной или предыдущей? То есть, если у пациента было три приема, следует ли сравнивать третье посещение с первым или вторым?
У вас первая проблема, о которой я и ответил. Если это не так, вы захотите использовать
lag
.Кроме того, имейте в виду, что
DateDiff
не исключение для выходных. Если это будут только будние дни, вам нужно будет создать свою собственную функцию Scalar-Valued.источник
используя функцию запаздывания
Демо -> https://rextester.com/TNW43808
источник
apptDate
в качествеorder by
столбцаlag
функции (что на самом деле должно быть, поскольку идентификатор ничего не гарантирует), его все равно можно легко сломать, введя дополнительные последующие встречи. Посмотрите эту демонстрацию Rextester, например. Хорошая попытка, хотя ...New
а не аFollowUp
. Прошло более 30 дней с момента первого приема этого пациента ... Вы должны сосчитать 30 дней после каждогоNew
посещения, а затемNew
снова использовать ...Мой правильный. Авторы были неверны, см. Истекшие
источник