Как проверить, существуют ли данные в нескольких таблицах (каждая из которых имеет один и тот же столбец)? - PullRequest
11 голосов
/ 29 августа 2011

У меня есть 3 таблицы, каждая из которых состоит из столбца с именем пользователя.Что касается регистрации, мне нужно проверить, что запрошенное имя пользователя является новым и уникальным.

Мне нужен тот единственный SQL, который сообщит мне, существует ли этот пользователь в любой из этих таблиц, прежде чем я продолжу.Я попытался:

SELECT tbl1.username, tbl2.username, tbl3.username
FROM tbl1,tbl2,tbl3
WHERE tbl1.username = {$username}
   OR tbl2.username = {$username}
   OR tbl3.username ={$username}

Это путь?

Ответы [ 7 ]

22 голосов
/ 29 августа 2011
select 1 
from (
    select username as username from tbl1
    union all
    select username from tbl2
    union all
    select username from tbl3
) a
where username = 'someuser'
14 голосов
/ 29 августа 2011

Если вы, честно говоря, просто хотите узнать, существует ли пользователь:

Самый быстрый подход - это запрос на существование:

select 
NOT EXISTS (select username from a where username = {$username}) AND 
NOT EXISTS (select username from b where username = {$username}) AND 
NOT EXISTS (select username from c where username = {$username});

Если ваш username столбец помечен как Unique в каждой таблице, это должен быть самый эффективный запрос, который вы сможете выполнить для выполнения этой операции, и этот превзойдет нормированную таблицу имен пользователей с точки зрения использования памяти ину, фактически, любой другой запрос, который заботится о username и другом столбце, поскольку нет чрезмерных объединений.Если вас когда-либо призывали ускорить работу базы данных организации, могу вас заверить, что чрезмерная нормализация - это кошмар.В отношении совета, который вы получили по нормализации в этой теме, будьте осторожны.Это отлично подходит для ограничения пространства или ограничения количества мест, в которых вы должны обновлять данные, но вы должны взвесить это в сравнении с затратами на обслуживание и скорость.Примите совет, данный вам на этой странице, с недоверием.

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

Если вы хотите добавить пользователя позже:

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

INSERT INTO {$table} (`username`, ... )
  SELECT {$username} as `username`, ... FROM DUAL 
   WHERE 
     NOT EXISTS (select username from a where username = {$username}) AND 
     NOT EXISTS (select username from b where username = {$username}) AND 
     NOT EXISTS (select username from c where username = {$username});

Все API баз данных, которые я видел, а также все реализации SQL предоставят вам способ узнать, сколько строк было вставлено.Если это 1, то имя пользователя не существует и вставка прошла успешно.В этом случае я не знаю ваш диалект, и поэтому я выбрал MySQL, который предоставляет таблицу DUAL специально для возврата результатов, которые не привязаны к таблице, но, честно говоря, есть много способов сделать этоcat, независимо от того, помещаете ли вы это в транзакцию или хранимую процедуру, или строго ограничиваете процесс и процедуру, которые могут обращаться к этим таблицам.

Обновление - Как обращаться с пользователями, которые не завершили подписьup process

Как указывает @RedFilter, если регистрация выполняется в несколько этапов - резервирование имени пользователя, заполнение информации, возможно, ответ на подтверждение по электронной почте, тогда вы захотите хотя бы добавить столбецпометить этого пользователя (с отметкой времени, а не с логическим значением), чтобы вы могли периодически удалять пользователей через некоторое время, хотя я рекомендую создать таблицу ToBePurged и добавить в нее новых пользователей вместе с отметкой времени.Когда подтверждение приходит, вы удаляете пользователя из этой таблицы.Периодически вы будете проверять эту таблицу на наличие всех записей до некоторой разницы с текущим временем и просто удалять их из той таблицы, в которую они были первоначально добавлены.Моя философия заключается в том, чтобы более четко определить ответственность таблицы и сохранить количество записей, с которыми вы работаете, очень скудным.Мы, конечно, не хотим чрезмерно проектировать наши решения, но если вы привыкнете к хорошим архитектурным практикам, эти проекты будут развиваться так же естественно, как и их менее эффективные аналоги.

2 голосов
/ 29 августа 2011

Нет. Два процесса могут запустить ваш тест одновременно, и оба будут сообщать об отсутствии пользователя, а затем оба смогут вставить одного и того же пользователя.

Похоже, вам нужна единственная таблица, чтобы хранить ВСЕХ пользователей с уникальным индексом для предотвращения дублирования. Эта основная таблица может ссылаться на «вложенные таблицы» с использованием идентификатора пользователя, а не имени пользователя.

1 голос
/ 29 августа 2011

Учитывая параметры сортировки, вы можете сделать это вместо этого, если вы не хотите иметь дело с несовпадением параметров сортировки:

select sum(usercount) as usercount
from (
    select count(*) as usercount from tbl1 where username = 'someuser'
    union all
    select count(*) as usercount from tbl2 where username = 'someuser'
    union all
    select count(*) as usercount from tbl3 where username = 'someuser'
) as usercounts

Если вы получите 0, то пользователь с таким именем пользователя не найдется, если вы получаете что-то более высокое, то есть.

Примечание. В зависимости от того, как вы выполняете вставку, теоретически вы можете получить более одного пользователя с одним и тем же именем пользователя из-за условий гонки (см. другие комментарии о нормализации иуникальные ключи).

1 голос
/ 29 августа 2011

1 - Вам нужно нормализовать ваши таблицы

См .: http://databases.about.com/od/specificproducts/a/normalization.htm

2- Не используйте неявные объединения SQL '89.

Откажись от привычки и используй явные соединения

SELECT a.field1, b.field2, c.field3
FROM a
INNER JOIN b ON (a.id = b.a_id)  -- JOIN criteria go here
INNER JOIN c ON (b.id = c.b_id)  -- and here, nice and explicit.
WHERE ... -- filter criteria go here.
0 голосов
/ 29 августа 2011

С вашей текущей настройкой ответ RedFilter должен работать нормально.Я подумал, что стоит отметить, что вы не должны иметь избыточных или разрозненных данных в своей базе данных для начала.

У вас должно быть одно и только одно место для хранения каких-либо конкретных данных - так что в вашем случаевместо того, чтобы иметь имя пользователя в 3 разных таблицах, у вас должна быть одна таблица с именем пользователя и идентификатором первичного ключа для этих имен пользователей.Ваши остальные 3 таблицы должны затем ссылаться на внешний ключ таблицы имен пользователей.С этим макетом вы сможете создавать гораздо более простые и эффективные запросы.Вы открываете банку с червями, копируя данные в разных местах.

0 голосов
/ 29 августа 2011

Вы можете просто разбить его на три запроса ...

if ($db->select('table1', '*', 'username='$username)) {

 //record found .. so not unique

} else {

 //check next table
 if ($db->select('table2', '*', 'username='$username)) {

    //record found .. so not unique 

 } else {

   //check next table ... etc ...

}

Это было бы самым простым, но, возможно, не самым элегантным решением ... Что вам действительно нужно сделать, это нормализовать вашу базу данных ...

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