SQL - Как извлечь запись из подзапроса, только если все записи имеют определенное значение - PullRequest
0 голосов
/ 24 октября 2018

Учитывая 2 таблицы.

PR 

prnum | col2        | col3
-------------------------
 1001 | Khar        | 5
 2002 | SantaCruz   | 3
 3200 | Sion        | 2
 4321 | VT          | 1

и

PRLine

prnum | prlinenum | status
------------------------------
 1001 | 1         | INWILLCALL
 1001 | 2         | ORDERED
 2002 | 1         | ORDERED
 2002 | 2         | ORDERED
 2002 | 3         | ORDERED
 3200 | 1         | INWILLCALL
 3200 | 2         | INWILLCALL

Я хотел бы выбрать все PRNUM из таблицы PR, где ВСЕ соответствующие записи, содержащиеся в таблице PRLINE, имеют статусof INWILLCALL.

В приведенных выше таблицах должен быть возвращен только PRNUM 3200.

На данный момент у меня есть:

select * from PR WHERE
status not in ('CAN','CLOSED','COMP','DRAFT')
and prnum in (select prnum from prline where status = 'INWILLCALL');

, что явно неверно.

Может кто-нибудь помочь, пожалуйста?

Спасибо

Ответы [ 6 ]

0 голосов
/ 24 октября 2018

ВЫБРАТЬ prnum ОТ PR JOIN prline на pr.prnum = prline.prnum WHERE prline.status = 'inwillcall' GROUP BY prnum

Объединение обеспечит получение совместных записей из двух таблиц.Условие фильтра на второй таблице будет гарантировать, что будут возвращены только те, кто имеет "inwillcall".Группировка по - это способ отфильтровать дубликаты.Надеюсь это поможет!

0 голосов
/ 24 октября 2018

Вы можете попробовать это тоже, просто по-другому:

SELECT DISTINCT  prnum FROM
(SELECT  'INWILLCALL' AS te,p.prnum,pr.status,lead(pr.status) OVER (PARTITION BY p.prnum ORDER BY pr.status)leadvalue FROM #PR AS p
INNER JOIN #PRLine  as pr   ON p.prnum = pr.prnum)m
WHERE leadvalue = status
AND status = 'INWILLCALL'
0 голосов
/ 24 октября 2018

Я бы использовал GROUP BY предложение:

SELECT prnum
FROM PRLine 
GROUP BY prnum
HAVING SUM(CASE WHEN Status <> 'INWILLCALL' THEN 1 ELSE 0 END) = 0;

Другой вариант - использовать агрегатную функцию twise:

SELECT prnum
FROM PRLine 
GROUP BY prnum
HAVING MIN(Status) = MAX(Status) AND MIN(Status) = 'INWILLCALL';
0 голосов
/ 24 октября 2018

Еще одна опция: коррелированный подзапрос с использованием WITH NOT EXISTS.Это защитит вас от проблем с NOT IN в случае значения NULL в status.

select 
  prnum
from 
  @PRLine as prl
where 
  not exists 
    (select 1 
     from 
      @PRLine prl2 
     where 
      prl2.status <> 'INWILLCALL' 
      and prl2.prnum = prl.prnum)
group by prnum;
0 голосов
/ 24 октября 2018

Несколько других опций, которые вы можете попробовать:

DECLARE @PR TABLE
    (
        [prnum] INT
      , [col2] NVARCHAR(100)
      , [col3] INT
    );
INSERT INTO @PR (
                    [prnum]
                  , [col2]
                  , [col3]
                )
VALUES ( 1001, ' Khar        ', 5 )
     , ( 2002, ' SantaCruz   ', 3 )
     , ( 3200, ' Sion        ', 2 )
     , ( 4321, ' VT          ', 1 );

DECLARE @PRLine TABLE
    (
        [prnum] INT
      , [prlinenum] INT
      , [status] NVARCHAR(100)
    );
INSERT INTO @PRLine (
                        [prnum]
                      , [prlinenum]
                      , [status]
                    )
VALUES ( 1001, 1, 'INWILLCALL' )
     , ( 1001, 2, 'ORDERED' )
     , ( 2002, 1, 'ORDERED' )
     , ( 2002, 2, 'ORDERED' )
     , ( 2002, 3, 'ORDERED' )
     , ( 3200, 1, 'INWILLCALL' )
     , ( 3200, 2, 'INWILLCALL' );


--Option 1
SELECT     [a].[prnum]
FROM       @PR [a]
INNER JOIN @PRLine [b]
    ON [b].[prnum] = [a].[prnum]
GROUP BY   [a].[prnum]
HAVING     MIN([b].[status]) = MAX([b].[status])
           AND MIN([b].[status]) = 'INWILLCALL';

--Option 2
SELECT     DISTINCT [a].[prnum]
FROM       @PR [a]
INNER JOIN @PRLine [b]
    ON [b].[prnum] = [a].[prnum]
WHERE      [b].[status] = 'INWILLCALL'
           AND [a].[prnum] NOT IN (
                                      SELECT [prnum]
                                      FROM   @PRLine
                                      WHERE  [status] <> 'INWILLCALL'
                                  );
0 голосов
/ 24 октября 2018

Вы можете попытаться использовать функцию агрегата условий в HAVING, чтобы получить prnum, который status - это все 'INWILLCALL'

select *
from PR 
WHERE prnum  IN (
    SELECT prnum 
    FROM PRLine
    GROUP BY prnum
    HAVING COUNT(CASE WHEN status = 'INWILLCALL' THEN 1 END) = COUNT(*)
)

sqlfiddle

...