Логический оператор SQL для битовых полей - PullRequest
0 голосов
/ 28 января 2009

У меня есть 2 таблицы, которые имеют отношение многие ко многим; Индивидуум может принадлежать ко многим группам. Группа может иметь много людей.

Физические лица в основном просто имеют свой идентификатор первичного ключа

Группы имеют идентификатор первичного ключа, IndividualID (такой же, как идентификатор в индивидуальной таблице) и битовый флаг, если эта группа является основной группой для отдельного человека

Теоретически, для всех, кроме одной записи для любого отдельного человека в таблице групп, этот битовый флаг должен иметь значение false, поскольку у каждого человека должна быть ровно 1 первичная группа.

Я знаю, что для моего текущего набора данных это предположение не выполняется, и у меня есть несколько людей, у которых первичный флаг для ВСЕХ их групп установлен в false.

У меня проблемы с генерацией запроса, который вернет мне этих людей.

Самое близкое, что я получил:

ВЫБРАТЬ * ОТ ЛИЧНОГО Я ЛЕВАЯ РЕГИСТРАЦИЯ Группа g ON g.IndividualID = i.ID ГДЕ g.IsPrimaryGroup = 0

, но идти дальше, чем с SUM или MAX, не работает, потому что поле является битовым полем, а не числовым.

Есть предложения?

Ответы [ 7 ]

1 голос
/ 28 января 2009

Обновление: получил работу с подвыбором. Выберите IndividualID из группы, в которой основная группа имеет значение false, а IndividualID NOT IN (выберите IndividualID из группы, где основная группа имеет значение true)

1 голос
/ 28 января 2009

Попробуйте не использовать битовое поле, если вам нужно использовать SUM и MAX - используйте вместо этого TINYINT. Кроме того, насколько я помню, битовые поля не могут быть проиндексированы, поэтому вы потеряете некоторую производительность в своих объединениях.

1 голос
/ 28 января 2009

Не знаю ваших данных ... но .... это ЛЕВОЕ СОЕДИНЕНИЕ - ВНУТРЕННЕЕ СОЕДИНЕНИЕ

что происходит, когда вы меняете WHERE на AND

SELECT * FROM Individual i 
LEFT JOIN Group g ON g.IndividualID = i.ID 
AND g.IsPrimaryGroup = 0

Здесь попробуйте запустить это .... без проверки, конечно, поскольку вы не предоставили достаточно данных

SELECT SUM(convert(int,g.IsPrimaryGroup)), i.ID 
FROM Individual i 
LEFT JOIN [Group] g ON g.IndividualID = i.ID 
AND g.IsPrimaryGroup = 0
GROUP BY i.ID
HAVING COUNT(*) > 1
0 голосов
/ 29 января 2009
SELECT IndividualID
FROM Group g
WHERE NOT EXISTS (
    SELECT NULL FROM Group
    WHERE PrimaryOrg = 1
    AND IndividualID = g.IndividualID)
GROUP BY IndividualID
0 голосов
/ 29 января 2009

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

ВЫБЕРИТЕ DISTINCT (i.IndividualID)
ОТ
Индивидуальный ВНУТРЕННИЙ РЕЙТИНГ OrgIndividual oi
ON i.IndividualID = oi.IndividualID AND oi.PrimaryOrg = 0
LEFT JOIN OrgIndividual oip
ON oi.IndividualID = oip.IndividualID AND oi.PrimaryOrg = 1
ГДЕ
oi2.IndividualID IS NULL

0 голосов
/ 28 января 2009
SELECT COUNT(bitflag),individualId 
FROM Groups
WHERE bitflag = 1
GROUP BY individualId
ORDER BY SUM(bitFlag)
HAVING COUNT(bitFlag) <> 1

Это даст вам каждого человека и сколько у них основных групп

0 голосов
/ 28 января 2009

Вам необходимо включить условие IsPrimaryGroup в предложение JOIN. Этот запрос находит всех людей без установленной группы PrimaryGroup:

SELECT * FROM Individual i
LEFT OUTER JOIN Group g ON g.IndividualID = i.ID AND g.IsPrimaryGroup = 1
WHERE g.ID IS NULL

Тем не менее, идеальный способ решения вашей проблемы (с точки зрения реляционной базы данных) - это указать PrimaryGroupID в таблице Individual.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...