отдельный SQL-запрос - PullRequest
       8

отдельный SQL-запрос

0 голосов
/ 03 марта 2009

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

Я пытаюсь извлечь из него данные, чтобы: Если две строки имеют одно и то же имя , но в одной из них указан адрес электронной почты, заканчивающийся на «@ yahoo.com», а в другой - другой адрес электронной почты, то тот, который имеет адрес электронной почты «@ yahoo.com», должен быть отброшенным.

Каков наилучший способ получить эти данные?

Ответы [ 8 ]

3 голосов
/ 03 марта 2009

Хорошо, я не собираюсь ввязываться в еще одну драку с теми, кто говорит, что я не должен защищать изменения схемы базы данных (да, вы знаете, кто вы :-), но вот как я это сделаю.

1 / Если вы абсолютно не можете изменить схему, я бы решил ее с помощью кода (либо реального процедурного кода, основанного на добросовестности, за пределами базы данных, либо в виде хранимой процедуры на любом языке, который позволяет ваша СУБД).

Это проверит базу данных на имя, отличное от Yahoo, и вернет его, если оно есть. Если бы не там, он попытался бы вернуть имя Yahoo. Если ни того, ни другого нет, будет возвращен пустой набор данных.

2 / Если вы можете изменить схему и хотите, чтобы SQL-запрос выполнял эту работу, вот как я это сделаю. Создайте в вашей таблице отдельный столбец с именем CLASS, для которого, как ожидается, будет установлено значение 0 для адресов, отличных от Yahoo, и 1 для адресов Yahoo.

Создание триггеров вставки / обновления для проверки каждого добавления или изменения строки, установка КЛАССА на основе адреса электронной почты (чем он заканчивается). Это гарантирует, что CLASS всегда будет установлен правильно.

Когда вы запрашиваете таблицу, упорядочиваете ее по имени и классу и выбираете только первую строку. Это даст вам адрес электронной почты в следующем предпочтении: не-Yahoo, Yahoo, пустой набор данных.

Что-то вроде:

select name, email
from tbl
where name = '[name]'
order by name, class
fetch first row only;

Если ваша СУБД не имеет эквивалента предложению DB2 «только для первой строки», вам, вероятно, все равно потребуется написать код для обработки только одной записи.

Если вы хотите обработать все имена, но только определенную желаемую электронную почту для этого имени, такой программы будет достаточно (мои взгляды на попытки использовать реляционную алгебру, такую ​​как SQL, процедурным способом довольно жестоки, поэтому я здесь их не навязать):

# Get entire table contents sorted in name/class order.
resultSet = execQuery "select name, email from tbl order by name, class"

# Ensure different on first row
lastName = resultSet.value["name"] + "X"

# Process every single row returned.
while not resultSet.endOfFile:
    # Only process the first in each name group (lower classes are ignored).
    if resultSet.value["name"] != lastName:
        processRow resultSet.value["name"] resultSet.value["email"]
    # Store the last name so we can detect next name group.
    lastName = resultSet.value["name"]
1 голос
/ 03 марта 2009
select ne.*
from name_email ne
where ne.email not like '%@yahoo.com' escape '\' or
    not exists(
               select 1 from name_email
               where name = ne.name and
               email not like '%@yahoo.com' escape '\'
              )
0 голосов
/ 03 марта 2009

Вы можете использовать СОЮЗ для этого. Выберите все без yahoo.com, а затем просто выберите записи, у которых есть yahoo.com и которых нет в первом списке.

ВЫБЕРИТЕ DISTINCT (name, name_email) ИЗ TABLE ГДЕ name_email НЕ '% yahoo.com' UNION ВЫБЕРИТЕ DISTINCT (name, name_email) ИЗ ТАБЛИЦЫ ГДЕ НЕ ВХОДИТЕ (ВЫБЕРИТЕ DISTINCT (name, name_email) ИЗ TABLE ГДЕ name_email НЕ '% yahoo.com')

0 голосов
/ 03 марта 2009

Если вы работаете с SQL Server 2005 или Oracle, вы легко можете решить свою проблему с помощью ранжирующей (аналитической) функции.

select a.name, a.name_email
from (select name, name_email,
             row_number() over (partition by name
                                order by case
                                           when name_email like '%@yahoo.com' then 1
                                           when name_email like '%@gmail.com' then 1
                                           when ... (other 'generic' email) then 1
                                           else 0
                                         end) as rn) as a
where a.rn = 1

Присваивая различные значения различным родовым именам электронной почты, вы даже можете иметь «настройки». Как написано здесь, если у вас есть адрес Yahoo и Gmail, вы не можете предсказать, какой из них будет выбран.

0 голосов
/ 03 марта 2009

Не очень красиво, но я считаю, что это должно работать

select 
    ne.name 
    ,ne.email
from 
    name_email ne
    inner join (
        select 
            name 
            ,count(*) as emails_per_name
        from 
            name_email
        group by name
    ) nec 
        on ne.name = nec.name
where
    nec.emails_per_name = 1
    or (nec.emails_per_name > 1 and ne.email not like ('%@yahoo.com'))

Это предполагает, что дубликаты электронных писем будут находиться в домене yahoo.com - как указано в вашем вопросе, и они будут исключены, если на одно имя будет приходиться более одного письма

0 голосов
/ 03 марта 2009

Получение всех строк из базы данных, не зная, каковы имена (и не нужно заботиться об этом на самом деле), но просто хочу, чтобы они отображались, и, если они совпадают, пропустите совпадение, если электронное письмо содержит, в этом случае , @yahoo.com

SELECT DISTINCT name, email FROM name_email 
  WHERE email NOT LIKE '%@yahoo.com' 
  GROUP BY name;

Выполнение этого захватит все строки, но только одну запись, если имена совпадают с другой строкой. Но затем, если есть две строки с совпадающими именами, отбросьте в письме одну строку с @yahoo.com.

0 голосов
/ 03 марта 2009

Вы могли бы сделать

SELECT TOP 1 email
FROM name_email
WHERE name = 'Joe Guy'
ORDER BY case when email like '%yahoo.com' then 1 else 0 end

Сортируйте их по порядку *@yahoo.com в последнюю очередь и по первому, а затем по первому.

РЕДАКТИРОВАТЬ: извините, неправильно прочитал вопрос - вы хотите список каждого имени, только один адрес электронной почты и предпочтение для электронных писем не Yahoo. Вероятно, можно использовать вышеупомянутое вместе с группой, мне придется переосмыслить это.

0 голосов
/ 03 марта 2009

Вы можете использовать что-то вроде следующего, чтобы исключить недействительные адреса электронной почты:

SELECT name, email
FROM name_email
WHERE email NOT LIKE '%@yahoo.com' // % symbol is a wildcard so joe@yahoo.com and guy@yahoo.com both match this query.
AND name = 'Joe Guy';

Или добавьте только действительный адрес электронной почты или домен:

SELECT name, email
FROM name_email
WHERE email LIKE '%@gmail.com'
AND name = 'Joe Guy';

Это хорошо работает, если вы заранее знаете, для каких конкретных имен вы запрашиваете и какие адреса электронной почты или домены вы хотите исключить или включить.

Или, если вам все равно, какой адрес электронной почты вы возвращаете, а хотите вернуть только один, вы можете использовать что-то вроде этого:

SELECT DISTINCT (name, email)
FROM name_email;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...