2011-03-12 53 views
4

我要写符合下列要求的查询:多加入语句不返回预期的结果

查询应返回所有 项值的列表名为 “史蒂夫”的客户,并为每显示日期(如果有 可用) 该日期的最新状态详情。

客户表

CustomerID | CustomerName 
1   | Steve 
2   | John 

项目表

CustomerID | EntryDate | EntryValue 
1   | 5/4/2010 | 200.0 
1   | 4/4/2010 | 100.0 
1   | 3/4/2010 | 150.0 
1   | 2/4/2010 | 170.0 
2   | 5/4/2010 | 220.0 

状态表

CustomerID | StatusDate | Detail 
1   | 5/28/2010 | D 
1   | 4/24/2010 | S 
1   | 4/5/2010 | P 
1   | 2/28/2010 | A 

预期的输出是:

CustomerName | Date | OrderCost | Detail 
    Steve  | 5/4/2010 | 200.0 | S 
    Steve  | 4/4/2010 | 100.0 | A 
    Steve  | 3/4/2010 | 75.0  | A 
    Steve  | 3/4/2010 | 75.0  | <null> 

我认为,预期的输出可能是错误的,它实际上应该是:

CustomerName | Date | OrderCost | Detail 
    Steve  | 5/4/2010 | 200.0 | S 
    Steve  | 4/4/2010 | 100.0 | A 
    Steve  | 3/4/2010 | 150.0  | A 
    Steve  | 2/4/2010 | 170.0  | <null> 

考虑的要求,我不明白为什么3/4/2010日期会发生两次,第二次会有一个详细信息。我写了下面的查询:

我写了下面的查询:

SELECT Customers.CustomerName, Entries.EntryDate, Entries.EntryValue, Status.Detail 
FROM Customers 
    INNER JOIN Entries ON Customers.CustomerID = Entries.CustomerID 
    LEFT OUTER JOIN Status ON Status.CustomerID = Customers.CustomersID AND Status.StatusDate <= Entries.EntryDate 
WHERE (Customers.CustomerName = 'Steve') 

我查询的结果是这样的:

CustomerName| EntryDate | EntryValue | Detail 
Steve  | 5/4/2010 | 200.00 | S 
Steve  | 5/4/2010 | 200.00 | P 
Steve  | 5/4/2010 | 200.00 | A 
Steve  | 4/4/2010 | 100.00 | A 
Steve  | 3/4/2010 | 150.00 | A 
Steve  | 2/4/2010 | 170.00 | NULL 

任何提示上,我做错了什么在这里?我无法弄清楚...

更新 我已经改变了顺序到一个条目,所以它不会混淆我们那么多。

+0

这是功课?如果是这样,也许给定的输出只是一个例子,并不完全是你需要得到的。订单成本为75.0的订单中没有看到任何条目。 – 2011-03-12 04:04:17

+0

@Bertrand:OP输出中5/4/2010订单的状态详细信息不正确。有3行返回,每个都有不同的状态详细信息,而不是一行状态详细信息为“已发​​货”。 – 2011-03-12 04:10:01

+0

@Mattt,我会检查我的输出结果......我手工复制了很多这些东西,所以我可能会犯一个错字。 – Kiril 2011-03-12 04:27:01

回答

1

由于第二个JOIN条件由状态表中的许多行满足(例如,有3个状态日期早于5/4,所以此日期在结果集中显示3次),所以得到的结果比您预期的要多。

您需要加入状态表,但只能获得一个匹配项(最新)。这可以通过几种方式完成,AFAIK通常使用子查询。我认为你的情况相当复杂 - 我使用了临时表。希望它有帮助...(我目前没有数据库来测试这个,希望没有愚蠢的语法错误)。

DROP TABLE IF EXISTS temp; 

CREATE TABLE temp AS -- This temp table is basically the result set you got 
(SELECT c.CustomerName, e.EntryDate, e.EntryValue, s.Detail, s.StatusDate 
    FROM Customers c 
    INNER JOIN Entires e ON c.CustomerID = e.CustomerID 
    LEFT OUTER JOIN Status s ON s.CustomerID = c.CustomersID 
        AND s.StatusDate <= e.EntryDate 
    WHERE (c.CustomerName = 'Steve') 
); 

SELECT t.CustomerName, t.EntryDate, t.EntryValue, t.Detail 
FROM temp t 
WHERE t.StatusDate = (SELECT MAX(t2.StatusDate) 
         FROM temp t2 
         WHERE t2.EntryDate = t.EntryDate); 

要创建一个临时表,我相信这将避免工作(请尽量不要让我知道!)

SELECT t.CustomerName, t.EntryDate, t.EntryValue, t.Detail 
FROM (SELECT c.CustomerName, e.EntryDate, e.EntryValue, s.Detail, s.StatusDate 
     FROM Customers c 
     INNER JOIN Entries e ON c.CustomerID = e.CustomerID 
     LEFT OUTER JOIN Status s ON s.CustomerID = c.CustomersID 
         AND s.StatusDate <= e.EntryDate 
     WHERE c.CustomerName = 'Steve') AS t 
WHERE t.StatusDate = (SELECT MAX(t2.StatusDate) 
         FROM temp t2 
         WHERE t2.EntryDate = t.EntryDate); 
+0

有没有办法将这个查询用作另一个查询的输入(即避免创建临时表)? – Kiril 2011-03-13 20:30:55

+0

@Lirik是的,我认为这总是一个选项 - 请记住,如果有大量数据,子查询往往会使其变得非常流畅。我将编辑添加一个没有临时表的选项。 – Galz 2011-03-13 20:42:35

+0

我试过了,但Select语句出现错误:“无效的列名'EntryDate'”......我能够让Richar的查询工作(只需稍作修改)。 – Kiril 2011-03-13 22:46:12

0

状态日期不应该在订单日期之后?喜欢的东西:

SELECT Customers.CustomerName, Orders.OrderDate, Orders.OrderCost, Status.Detail 
FROM Customers 
    INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID 
    LEFT OUTER JOIN Status ON Status.CustomerID = Customers.CustomersID 
WHERE Customers.CustomerName = 'Steve' AND Status.StatusDate >= Orders.OrderDate 

此外,在StatusCustomerID似乎有点陌生,因为它通常是有一个状态,而不是客户的订单。状态表不应该有OrderID字段吗?

+0

关于状态/订单ID:我不得不更改列,表和数据的名称有点因为信息是专有的......我试图想出合理的选择,但我很抱歉,如果他们不是一切都很棒。否则,当前结构是实际数据库结构的准确表示。 – Kiril 2011-03-12 04:38:05

+0

我应该想出更好的名字,但“订购日期”实际上是在“状态日期”之后......如果这是一个问题,那么我会提出更好的名字。 – Kiril 2011-03-12 04:43:31

0

预期的输出是错误的。最后一行应该是2010年4月2日的日期。另外,他们的订单成本也不对。 2/4/2010应该返回null,因为没有匹配的状态。

+0

我已经更新了一些表(更改名称,所以它更少混淆)...我仍然无法弄清楚如何构建我的查询寿。 – Kiril 2011-03-12 18:44:03

1

您可以使用子查询来获取状态。
为SQL Server或LIMIT 1的SQLite/MySQL的

的SQL Server使用TOP 1/sybase中

SELECT Customers.CustomerName, Entries.EntryDate, Entries.EntryValue, 
    (SELECT top 1 Status.Detail From Status 
    where Status.CustomerID = Customers.CustomersID AND Status.StatusDate <= Entries.EntryDate 
    order by Status.StatusDate desc) 
FROM Customers 
INNER JOIN Entries ON Customers.CustomerID = Entries.CustomerID 
WHERE (Customers.CustomerName = 'Steve') 

的MySQL/SQLite的

SELECT Customers.CustomerName, Entries.EntryDate, Entries.EntryValue, 
    (SELECT Status.Detail From Status 
    where Status.CustomerID = Customers.CustomersID AND Status.StatusDate <= Entries.EntryDate 
    order by Status.StatusDate desc 
    limit 1) 
FROM Customers 
INNER JOIN Entries ON Customers.CustomerID = Entries.CustomerID 
WHERE (Customers.CustomerName = 'Steve')