选择记录集中尚未存在的所有记录

时间:2011-09-19 13:53:21

标签: sql-server-2008

我正在使用的数据库当前有两个表,一个表包含属性“contact_person”。此属性与另一个名为“contact1”到“contact4”的表中的多个属性( not tuples!)进行比较,以确定从第二个表中显示的其他属性(即“email1”到“ EMAIL4" )。因此,第一个表只保存联系人,第二个表是几个联系人的实际地址数据(同样,所有这些都是连续的或单个元组)。不要告诉我这不是正确的数据库设计 - 我必须使用我给出的东西-.-

为了获得正确的联系人数据,我选择为每个比较执行选择并对它们进行UNION。这很好,并且对执行查询的应用程序执行得足够好。看起来很简单,就像这样:

SELECT contact1, email1, phone1 FROM T1,T2 WHERE contact_person = contact1
UNION ALL
SELECT contact2, email2, phone2 FROM T1,T2 WHERE contact_person = contact2
UNION ALL
SELECT contact3, email3, phone3 FROM T1,T2 WHERE contact_person = contact3
UNION ALL
SELECT contact4, email4, phone4 FROM T1,T2 WHERE contact_person = contact4

现在,由于格式错误且未经过错误检查的INSERT查询,“contact_person”可能为NULL或空字符串,或者任何“contactN”属性为NULL。所以我需要另一个SELECT查询来显示数据库中但尚未包含在记录集中的所有记录

使用与此类似的东西可以实现给定的示例:

UNION
SELECT contact_person, 'N/A', 'N/A' FROM T1,T2

在现实生活中,我(需要)做了很多“contact_person”和“contactN”的格式化,所以简单地做一个UNION(没有ALL,所以相同的记录被排除)不会工作(contactN是实际上是一个多字段值并且格式不一致,因此最后一个查询返回的记录可能与上面的记录不同,即使对于数据库中的相同条目也是如此。此外,查询已经非常庞大,因此无法使用第一个查询的相反方法来排除其记录,如下所示:

UNION ALL
SELECT contact_person, 'N/A', 'N/A' FROM T1,T2
    WHERE contact_person <> contact1
    AND contact_person <> contact2
    AND contact_person <> contact3
    AND contact_person <> contact4

那么是否有其他方法可以显示上面发布的第一个查询未选择的所有记录?也许通过某种方式运行子查询(ofc确实存在返回记录的UID - 我只是不知道如何在这种情况下使用它)?第一个查询是否可以用更简单的方式编写?

2 个答案:

答案 0 :(得分:2)

;WITH cp AS
(
    -- strongly recommend appropriate table prefixes in select list:
    SELECT UID, contact1, email1, phone1 
    -- also strongly recommend proper inner joins:
        FROM T1 INNER JOIN T2 ON t1.contact_person = t2.contact1
    UNION ALL
    SELECT UID, contact2, email2, phone2 
        FROM T1 INNER JOIN T2 ON t1.contact_person = t2.contact2
    UNION ALL
    SELECT UID, contact3, email3, phone3
        FROM T1 INNER JOIN T2 ON t1.contact_person = t2.contact3
    UNION ALL
    SELECT UID, contact4, email4, phone4 
        FROM T1 INNER JOIN T2 ON t1.contact_person = t2.contact4
)
SELECT contact1, email1, phone1 FROM cp
UNION ALL
SELECT t1.contact_person, 'N/A', 'N/A'
FROM T1 INNER JOIN T2 ON t1.contact_person = t2.contact1
WHERE UID NOT IN (SELECT UID FROM cp);

您可能还会考虑更规范化/关系设计?

答案 1 :(得分:1)

或者您可以先将T2标准化,然后再加入:

WITH normalisedT2 AS (
  SELECT
    contact = CASE x.n
      WHEN 1 THEN T2.contact1
      WHEN 2 THEN T2.contact2
      WHEN 3 THEN T2.contact3
      WHEN 4 THEN T2.contact4
    END,
    email = CASE x.n
      WHEN 1 THEN T2.email1
      WHEN 2 THEN T2.email2
      WHEN 3 THEN T2.email3
      WHEN 4 THEN T2.email4
    END,
    phone = CASE x.n
      WHEN 1 THEN T2.phone1
      WHEN 2 THEN T2.phone2
      WHEN 3 THEN T2.phone3
      WHEN 4 THEN T2.phone4
    END
  FROM T2
    CROSS JOIN (
      SELECT 1 UNION ALL
      SELECT 2 UNION ALL
      SELECT 3 UNION ALL
      SELECT 4
    ) x (n)
)
SELECT
  contact = T1.contact_person,
  email   = COALESCE(T2.email, 'N/A'),
  phone   = COALESCE(T2.phone, 'N/A')
FROM T1
  LEFT JOIN normalisedT2 T2 ON T1.contact_person = T2.contact