【问题标题】:distinct sql query不同的sql查询
【发布时间】:2009-03-03 05:16:14
【问题描述】:

我有一个简单的表,只有名称和电子邮件,名为 name_email。

我正在尝试从中获取数据,以便: 如果两行具有相同的名称,但其中一行的电子邮件以“@yahoo.com”结尾,而另一行的电子邮件不同,则那一行的电子邮件以“@yahoo.com”结尾应该被丢弃。

获取这些数据的最佳方法是什么?

【问题讨论】:

    标签: sql


    【解决方案1】:

    好的,我不会再与那些说我不应该提倡数据库架构更改的人打架了(是的,你知道你是谁 :-),但我会这样做。

    1/ 如果您绝对无法更改架构,我将使用代码解决它(数据库外部真正诚实的程序代码或作为 DBMS 允许的任何语言的存储过程)。

    这将检查数据库中的非雅虎名称并返回它,如果有的话。如果不存在,它将尝试返回 yahoo 名称。如果两者都不存在,它将返回一个空数据集。

    2/ 如果您可以更改架构并且希望 SQL 查询来完成这项工作,我会这样做。在您的表中创建一个名为 CLASS 的单独列,对于非雅虎地址,该列预计设置为 0,雅虎地址设置为 1。

    创建插入/更新触发器以检查行的每次添加或更改,根据电子邮件地址(以什么结尾)设置 CLASS。这保证了 CLASS 将始终正确设置。

    当您查询表时,按名称和类对其进行排序,并且只选择第一行。这将为您提供以下首选项的电子邮件地址:非雅虎、雅虎、空数据集。

    类似:

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

    如果您的 DBMS 没有等效于 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"]
    

    【讨论】:

    • 这是解决这个问题的正确方法。
    【解决方案2】:
    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 '\'
                  )
    

    【讨论】:

      【解决方案3】:

      您可以使用以下内容来排除无效的电子邮件地址:

      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;
      

      【讨论】:

      • 就是这样。我不知道名字提前:) 我正在寻找重复的名字。
      • 第二个使用 DISTINCT 运算符会更好吗?
      • 如果您有其他标准,例如每个拥有两个电子邮件地址的名称都应始终返回 x 电子邮件地址,那么请编辑您的问题以反映这一点。
      【解决方案4】:

      你可以的

      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 排序,然后按其他排序,然后取第一个。

      编辑:抱歉,误读了这个问题——你想要一个每个名字的列表,只有一封电子邮件,以及对非雅虎电子邮件的偏好。大概可以把上面的和group by一起用,我得重新考虑一下。

      【讨论】:

      • 这行得通,但我不是选择端每行处理的忠实粉丝。这是应该使用单独的列和触发器来完成的事情。根据我的经验,大多数表格的阅读频率远高于书面形式。设置排序顺序的插入/更新端过程更好 IMNSHO :-)。
      • 这与我的大型机背景有关,即使我们的配置表也使那些“较小”数据库的事务表相形见绌:-)
      【解决方案5】:

      从数据库中获取所有行,不知道名称是什么(并且不需要真正关心),但只是希望它们显示,如果匹配,如果电子邮件包含,则跳过匹配,在这种情况下, @yahoo.com

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

      这样做会抓取所有行,但如果名称与另一行匹配,则只会抓取一条记录。但是,如果有两行名称匹配,请在电子邮件中将带有 @yahoo.com 的那一行删除。

      【讨论】:

      • 如果你按名字分组,那么你必须有一个像 min(email) 这样的聚合函数另外,我相信如果这个人只有一封电子邮件并且它是一个雅虎电子邮件,他希望它返回。仅当存在重复项并且其中一个是 yahoo 他想要另一个时。
      • OPQ 读起来像是他想根据名称获取所有不同的行,而他事先并不知道。对于同名的一行,想要查看他们正在使用的电子邮件。如果其中之一与 yahoo.com 合作,那么放弃它并显示非雅虎的。
      【解决方案6】:

      不是很漂亮,但我相信它应该可以工作

      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 域中 - 如您的问题中所指定,如果每个名称有多个电子邮件,则这些将被排除

      【讨论】:

        【解决方案7】:

        如果您使用的是 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 地址,则无法预测会选择哪一个。

        【讨论】:

          【解决方案8】:

          您可以为此使用 UNION。选择没有 yahoo.com 的所有内容,然后只选择有 yahoo.com 且不在第一个列表中的记录。

          从表中选择 DISTINCT (name, name_email) WHERE name_email 不是 '%yahoo.com' 联盟 从表中选择 DISTINCT (name, name_email) WHERE name NOT IN (SELECT DISTINCT (name, name_email) FROM TABLE WHERE name_email 不是 '%yahoo.com')

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-11-20
            • 1970-01-01
            • 1970-01-01
            • 2016-12-24
            • 2011-03-18
            • 1970-01-01
            • 2013-08-09
            • 2017-10-18
            相关资源
            最近更新 更多