Из ответов здесь можно сделать вывод, что NOT IN (subquery)
неправильно обрабатывает нули и его следует избегать в пользу NOT EXISTS
. Однако такой вывод может быть преждевременным. В следующем сценарии, зачисленном в Chris Date (Database Programming and Design, Vol 2 No 9, September 1989), NOT IN
обрабатывает нули правильно и возвращает правильный результат, а не NOT EXISTS
.
Рассмотрим таблицу sp
для представления поставщиков (sno
), которые, как известно, поставляют детали (pno
) в количестве (qty
). В таблице в настоящее время хранятся следующие значения:
VALUES ('S1', 'P1', NULL),
('S2', 'P1', 200),
('S3', 'P1', 1000)
Обратите внимание, что количество является нулевым, т. Е. Для записи факта, что поставщик, как известно, предоставляет детали, даже если в каком количестве неизвестно.
Задача состоит в том, чтобы найти поставщиков, которые известны номером запасной части «P1», но не в количествах 1000.
Следующие правила используют NOT IN
для правильной идентификации поставщика S2, only:
WITH sp AS
( SELECT *
FROM ( VALUES ( 'S1', 'P1', NULL ),
( 'S2', 'P1', 200 ),
( 'S3', 'P1', 1000 ) )
AS T ( sno, pno, qty )
)
SELECT DISTINCT spx.sno
FROM sp spx
WHERE spx.pno = 'P1'
AND 1000 NOT IN (
SELECT spy.qty
FROM sp spy
WHERE spy.sno = spx.sno
AND spy.pno = 'P1'
);
Однако в нижеприведенном запросе используется одна и та же общая структура, но с NOT EXISTS
, но неверно включает в себя поставщик S1 в результате (т.е. для которого значение равно null):
WITH sp AS
( SELECT *
FROM ( VALUES ( 'S1', 'P1', NULL ),
( 'S2', 'P1', 200 ),
( 'S3', 'P1', 1000 ) )
AS T ( sno, pno, qty )
)
SELECT DISTINCT spx.sno
FROM sp spx
WHERE spx.pno = 'P1'
AND NOT EXISTS (
SELECT *
FROM sp spy
WHERE spy.sno = spx.sno
AND spy.pno = 'P1'
AND spy.qty = 1000
);
Таким образом, NOT EXISTS
не является серебряной пулей, она, возможно, появилась!
Конечно, источником проблемы является наличие нулей, поэтому «реальным» решением является устранение эти нули.
Это может быть достигнуто (среди других возможных конструкций) с использованием двух таблиц:
sp
поставщиков, которые, как известно, поставляют детали spq
поставщиков, которые, как известно, поставляют детали в известных количествах , отметив, что, вероятно, должно быть ограничение внешнего ключа, где spq
ссылается sp
.
Результат может тогда быть получена с использованием реляционного оператора «минус» (являющегося ключевым словом EXCEPT
в стандартном SQL), например
WITH sp AS
( SELECT *
FROM ( VALUES ( 'S1', 'P1' ),
( 'S2', 'P1' ),
( 'S3', 'P1' ) )
AS T ( sno, pno )
),
spq AS
( SELECT *
FROM ( VALUES ( 'S2', 'P1', 200 ),
( 'S3', 'P1', 1000 ) )
AS T ( sno, pno, qty )
)
SELECT sno
FROM spq
WHERE pno = 'P1'
EXCEPT
SELECT sno
FROM spq
WHERE pno = 'P1'
AND qty = 1000;
Если операция повышает исключение, что Ваш код не обрабатывает, BackgroundWorker
выгоды исключение и передает его в RunWorkerCompleted
обработчик событий, где оно представлено как свойство Error System.ComponentModel.RunWorkerCompletedEventArgs
. Если Вы будете работать под отладчиком Visual Studio, отладчик повредится в точке в обработчике событий DoWork, где необработанное исключение было повышено.
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.dowork.aspx
По умолчанию это будет поймано и сохранено BackgroundWorker. Из MSDN:
, Если операция повышает исключение, которое не обрабатывает Ваш код, BackgroundWorker ловит исключение и передает его в обработчик событий RunWorkerCompleted, где он представлен как свойство Error Системы. ComponentModel. RunWorkerCompletedEventArgs. Если Вы будете работать под отладчиком Visual Studio, отладчик повредится в точке в обработчике событий DoWork, где необработанное исключение было повышено.
Я полностью использую BackgroundWorker
в течение многих лет и действительно знать это глубоко.
Совсем недавно My RunWorkerCompleted
не обнаруживает e.Error
, когда я просто генерирую новое исключение («Тест»)
в DoWork
. Однако возникло необработанное исключение. Поймать в DoWork
- не лучшая практика, поэтому e.Error
не имеет смысла.
Когда я пытаюсь создать новую форму
с новым BackgroundWorker
, e.Error
в RunWorkerCompleted
обрабатывается успешно. В моем сложном BackgroundWorker
должно быть что-то не так.
Через несколько дней поисков в Google и отладки, попытка ошибки. Я нашел это в моем RunWorkerCompleted
:
e.Error
, затем e.Cancelled
и, наконец, e.Result
e.Result
, если e.Cancelled = True
. e.Result
, если e.Error
не равно null
(или Nothing
) ** ** Вот где я скучаю. Если вы пытаетесь использовать e.Result
, если e.Error
не равно null
(или Nothing
), будет сгенерировано необработанное исключение.
ОБНОВЛЕНИЕ:
В свойстве e.Result
get.NET спроектируйте его так, чтобы сначала проверить наличие e.Error
, если возникнет ошибка, они повторно вызовут то же исключение из DoWork
. Вот почему мы получаем необработанное исключение в RunWorkerCompleted
, но на самом деле исключение исходит из DoWork
.
Вот лучший способ сделать в RunWorkerCompleted
:
If e.Error IsNot Nothing Then
' Handle the error here
Else
If e.Cancelled Then
' Tell user the process canceled here
Else
' Tell user the process completed
' and you can use e.Result only here.
End If
End If
Если вам нужен объект, доступный для всех DoWork, ProgressChanged и RunWorkerCompleted, используйте это так:
Dim ThreadInfos as Dictionary(Of BackgroundWorker, YourObjectOrStruct)
Вы можете легко получить доступ к ] ThreadInfos (отправитель) .Field
где угодно.