Запрос, чтобы определить, существует ли идентификатор с определенным значением столбца в строках

#sql #sql-server-2014

#sql #sql-server-2014

Вопрос:

Мне нужно написать запрос для заказов на поставку и получить данные заголовка и строки. Это отношение «один ко многим», где существует одна строка заголовка PO_ID ( PS_PO_HDR ) к одной или нескольким связанным строкам ( PS_PO_LINE ) через PO_ID идентификатор. Мне нужно, чтобы запрос исключал строки, где значение CANCEL_STATUS равно «X», ЕСЛИ это не одно и то же PO_ID , и BUSINESS_UNIT имеет другие строки со значениями, CANCEL_STATUS отличными от X' .

По сути, мне нужно иметь возможность запрашивать с использованием других критериев в моем запросе ниже (кроме конкретного PO_ID , который соответствует этому сценарию), который будет учитывать вышеуказанные критерии. Если PO_ID / BUSINESS_UNIT имеет CANCEL_STATUS значение ‘X’ во всех его строках, я не хочу, чтобы это PO_ID было включено в результаты.

Я бы хотел, чтобы приведенное ниже PO_ID было включено, потому что, хотя у него есть строка с CANCEL_STATUS = 'X' , у него также есть другие строки CANCEL_STATUS с другими значениями (кроме ‘X’)

Как я могу определить PO_ID , где это происходит?

введите описание изображения здесь

 SELECT LINE.BUSINESS_UNIT, LINE.PO_ID, LINE.LINE_NBR, LINE.CANCEL_STATUS, LINE.CHANGE_STATUS
FROM PS_PO_LINE LINE
INNER JOIN PS_PO_HDR HEADER ON HEADER.BUSINESS_UNIT = LINE.BUSINESS_UNIT 
 AND HEADER.PO_ID = LINE.PO_ID
--ONLY USING THE FOLLOWING PO_ID FILTER TO ILLUSTRATE THIS EXAMPLE!!
WHERE LINE.PO_ID = 'A010027905'
 AND HEADER.PO_STATUS NOT IN ('C','X','PX')
 

Комментарии:

1. Я предполагаю, что цвета на вашем изображении присутствуют не случайно и что-то значат. Было бы полезно поделиться этим значением.

2. @GordonLinoff, я думаю, он просто выделил значения «X» против значений «C» и «A», чтобы подчеркнуть свою точку зрения. Определенный PO может содержать несколько строк, и каждая из этих строк может иметь разное значение CANCEL_STATUS. В случае с его примером, даже если одна строка имеет значение CANCEL_STATUS «X», поскольку другие строки не являются «X», тогда это значение должно появиться в результатах запроса. И наоборот, если это было так, что каждая строка для этого PO имела значение CANCEL_STATUS «X», то это PO не должно отображаться в результатах запроса

3. @Craig да, это именно то, чего я пытаюсь достичь.

Ответ №1:

Вы должны получить результаты, которые вам нужны, с помощью чего-то вроде этого

 SELECT LINE.BUSINESS_UNIT, LINE.PO_ID, LINE.LINE_NBR, LINE.CANCEL_STATUS, LINE.CHANGE_STATUS
FROM PS_PO_LINE LINE
INNER JOIN PS_PO_HDR HEADER ON HEADER.BUSINESS_UNIT = LINE.BUSINESS_UNIT 
 AND HEADER.PO_ID = LINE.PO_ID
WHERE EXISTS
(SELECT 1 FROM PS_PO_LINE AS [LineCheck] WHERE [LineCheck].PO_ID = HEADER.PO_ID AND [LineCheck].BUSINESS_UNIT = HEADER.BUSINESS_UNIT AND [LineCheck].CANCEL_STATUS != 'X');
 

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

Комментарии:

1. Кроме того, я не мог точно определить из вашего вопроса, хотите ли вы по-прежнему включать отмененную строку в фактические выходные результаты — в случае, когда есть хотя бы одна строка PO, которая не отменена. Мое решение, приведенное выше, дает вашему запросу логику, позволяющую решить, должен ли он выводить определенный результат или нет. Я уверен, что затем вы сможете добавить другие критерии по мере необходимости для достижения конечного результата

2. в этом случае я бы не хотел включать отмененную строку в выходные данные.

3. Понял. Итак, вы просто добавляете СТРОКУ И. CANCEL_STATUS != ‘X’ в конец запроса, чтобы эти строки фактически не были включены в выходные результаты

Ответ №2:

Вы должны быть в состоянии сделать что-то вроде этого. Использование exists для фильтрации строк — сравните количество строк для po_id с количеством строк, имеющих статус ‘X’, если значения отличаются, пропустите его.

 select l.BUSINESS_UNIT, l.PO_ID, l.LINE_NBR, l.CANCEL_STATUS, l.CHANGE_STATUS
from PS_PO_LINE l
inner join PS_PO_HDR h on h.BUSINESS_UNIT = l.BUSINESS_UNIT 
 and h.PO_ID = l.PO_ID
     where exists (
     select * from PS_PO_LINE x
     where x.po_id=l.po_id
     having Count(*) != Sum(case when cancel_status='X' then 1 else 0 end)
 )
 

Комментарии:

1. Не уверен, что это сработает, как следует из вашего ответа. Вы хотели сделать COUNT(*) != SUM(…. , или иначе это должно быть ТАМ, ГДЕ НЕ СУЩЕСТВУЕТ?

2. @craig да, вы правы, у меня было две версии, я тестировал одну с exists и not exists, я пропустил != ошибку копирования и вставки. Внесены изменения!