выберите строки, которые не имеют никаких внешних ключей связанными

break, как и goto, могут перемещаться только локально в пределах одной и той же функции, но если вам абсолютно необходимо, вы можете использовать setjmp и longjmp:

#include <stdio.h>
#include <setjmp.h>

jmp_buf jump_target;

void foo(void)
{
    printf("Inside foo!\n");
    longjmp(jump_target, 1);
    printf("Still inside foo!\n");
}

int main(void) {
    if (setjmp(jump_target) == 0)
        foo();
    else
        printf("Jumped out!\n");
    return 0;
}

Вызов на longjmp вызовет переход к вызову setjmp. Возвращаемое значение из setjmp показывает, возвращается ли оно после установки цели прыжка или возвращается с прыжка.

Вывод:

Inside foo!
Jumped out!

Нелокальные скачки безопасны при правильном использовании, но есть ряд вещей, о которых следует тщательно подумать:

  • Поскольку longjmp прыгает «через «все активации функций между вызовом setjmp и вызовом longjmp, если какая-либо из этих функций ожидает выполнения дополнительной работы после выполнения текущего места, эта работа просто не будет выполнена.
  • Если активация функции, вызвавшая setjmp, завершилась, поведение не определено. Все может случиться.
  • Если setjmp еще не был вызван, то jump_target не установлено, и поведение не определено.
  • Локальные переменные в функции, вызвавшей setjmp, могут при определенных условиях иметь неопределенные значения.
  • Одно слово: темы.
  • Другие вещи, такие как флаги состояния с плавающей запятой, могут не сохраняться, и есть ограничения на то, куда вы можете поместить вызов setjmp.

Большинство из них следуют естественным образом, если вы хорошо понимаете, что делает нелокальный переход на уровне машинных инструкций и регистров ЦП, но, если у вас нет этого, и прочитали, что Стандарт С делает и не гарантирует, я бы посоветовал немного предостеречь.

11
задан 26 May 2009 в 03:53
поделиться

3 ответа

Обновление

Я использовал четыре разных способа сделать это через SQL Server 2005 и включил план выполнения.

-- 269 reads, 16 CPU
SELECT *
FROM Groups
WHERE NOT EXISTS (
    SELECT *
    FROM People
    WHERE People.GroupId = Groups.GroupId
);

-- 249 reads, 15 CPU
SELECT *
FROM Groups
WHERE (
    SELECT COUNT(*)
    FROM People
    WHERE People.GroupId = Groups.GroupId
) = 0

-- 249 reads, 14 CPU
SELECT *
FROM Groups
WHERE GroupId NOT IN (
    SELECT DISTINCT GroupId
    FROM Users
)

-- 10 reads, 12 CPU
SELECT *
FROM Groups
    LEFT JOIN Users ON Users.GroupId = Groups.GroupId
WHERE Users.GroupId IS NULL

Итак, последний, хотя, возможно, наименее читаемый из четырех , работает лучше всего.

Это стало для меня неожиданностью, и, честно говоря, я по-прежнему предпочитаю синтаксис WHERE NOT EXISTS, потому что считаю его более явным - он читается в точности так, как вы пытаетесь сделать.

26
ответ дан 3 December 2019 в 02:11
поделиться

Мой предпочтительный метод - левое анти-полусоединение:

SELECT    g.*
FROM      Groups g
LEFT JOIN People p ON g.GroupID = p.GroupID
WHERE     p.GroupID IS NULL

Я считаю его наиболее интуитивным, гибким и производительным.

Я написал целую статью о различных стратегиях запросов для поиска в случае отсутствия данных - посмотрите здесь , если вам интересно.

6
ответ дан 3 December 2019 в 02:11
поделиться

Я думаю, что самое простое решение:

SELECT * 
FROM GROUPS
WHERE GroupId NOT IN (SELECT DISTINCT GroupId FROM People)
2
ответ дан 3 December 2019 в 02:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: