2011-09-19 97 views
2

我使用的数据库目前确实有两个表,一个拿着属性“contact_person”。此属性相比,它被命名为“contact1”到“contact4”,确定从第二个表显示什么其他属性在另一个表中的多个属性(不是元组!)(即“EMAIL1”到“EMAIL4”)。所以第一个表只保存联系人,第二个表是几个联系人的实际地址数据(再次,他们都在一行或一个元组中)。别告诉我,这AINT正确的数据库设计 - 我有我得到了-.-选择尚未在记录的所有记录

得到什么我选择执行选择每个比较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” S的格式,所以简单地做一个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
;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); 

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

+0

哦,我与表前缀工作,并加入 - 我只是试图保持它短而简单。此外,我不幸现在没有重新设计数据库的任何部分的选项。这只有在访问它的应用程序将被重写时才会发生,这是我目前工作的公司发现它具有必要的货币资源来执行此操作。我现在试图说服他们很长一段时间。无论如何,这看起来很像我需要的东西 - 只是我今天无法测试它(它在我们公司的关闭时间)。我会检查它并明天标记答案。谢谢。 –

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 
+0

工程就像一个魅力。我已经实施了Aarons版本,但它很高兴看到它以另一种方式解决。我没有时间比较两个版本的性能(只在一个小的测试数据库上实现你的版本),我只是出于兴趣和学习一点点。所以感谢和+1 –