3

我有 5 张桌子:

客户 ID - 姓名

p_orders id - id_customer - 代码 - 日期

p_items id - id_order - 描述 - 价格

和 h_orders 和 h_items,它们正是 p_orders 和 p_items 的副本。

当 p_ 表达到大量行时,我将最旧的表移至 h_ 表..它们作为历史记录。

所以,我的问题是:如何从 p_ 表和 h_ 中检索数据,将它们视为一个唯一表

例如,我想检索每个客户的订单数量和总价格(所有客户订单的),我使用该查询:

SELECT
    customer.id,
    customer.name,
    count(DISTINCT p_orders.id) AS num_orders,
    sum(p_items.price) AS total_money
FROM
    customer
    INNER JOIN p_orders ON p_orders.id_customer = customer.id
    INNER JOIN p_items ON p_items.id_order = p_orders.id
GROUP BY
    customer.id,
    customer.name,
    p_orders.id_customer
ORDER BY
    customer.id

它仅适用于一组“表”(p_ 或 h_)..但我都想要它们。

我尝试使用 UNION:

(
    SELECT
        customer.id,
        customer.name,
        count(DISTINCT p_orders.id) AS num_orders,
        sum(p_items.price) AS total_money
    FROM
        customer
        INNER JOIN p_orders ON p_orders.id_customer = customer.id
        INNER JOIN p_items ON p_items.id_order = p_orders.id
    GROUP BY
        customer.id,
        customer.name,
        p_orders.id_customer
)
UNION
(
    SELECT
        customer.id,
        customer.name,
        count(DISTINCT h_orders.id) AS num_orders,
        sum(h_items.price) AS total_money
    FROM
        customer
        INNER JOIN h_orders ON h_orders.id_customer = customer.id
        INNER JOIN h_items ON h_items.id_order = h_orders.id
    GROUP BY
        customer.id,
        customer.name,
        h_orders.id_customer
)
ORDER BY id ASC

这个可行,但如果客户在 p_ 表和 h_ 表中都有订单,我将为该客户提供 2 行具有 2 个不同的 num_orders 和 total_money (分别来自 p_ 表和 h_ 表)

我试图在联合之外添加一个 GROUP BY id:

(
    --SELECT 2
)
UNION
(
    --SELECT 1
)
GROUP BY id
ORDER BY id ASC

但是查询失败并出现ERROR: syntax error at or near "GROUP" at character 948,似乎 GROUP BY 不能以这种方式使用。

有什么建议吗?

编辑:

对于 uriDium,是的,所有表都将 id 列作为主键,并且引用的字段(又名 p_orders.id_customer)也是外键。这里是测试数据库结构转储(我在创建表后添加了一些索引和外键,但我不认为这意味着什么):

CREATE TABLE customer (
    id serial NOT NULL,
    name character(50)
);
CREATE TABLE p_orders (
    id serial NOT NULL,
    id_customer integer NOT NULL,
    date date DEFAULT now(),
    code character(5)
);
CREATE TABLE p_items (
    id serial NOT NULL,
    id_order integer NOT NULL,
    descr character(250),
    price money
);
CREATE TABLE h_orders (
    id integer NOT NULL,
    id_customer integer NOT NULL,
    date date,
    code character(5)
);
CREATE TABLE h_items (
    id integer NOT NULL,
    id_order integer NOT NULL,
    descr character(250),
    price money
);
CREATE UNIQUE INDEX id_h_orders ON h_orders USING btree (id);
CREATE INDEX id_h_o_c ON h_orders USING btree (id_customer);
CREATE UNIQUE INDEX id_items_h ON h_items USING btree (id);
CREATE INDEX id_ordinr_dsve ON h_items USING btree (id_order);

ALTER TABLE ONLY customer
    ADD CONSTRAINT customer_pkey  (id);
ALTER TABLE ONLY p_orders
    ADD CONSTRAINT p_orders_pkey PRIMARY KEY (id);
ALTER TABLE ONLY p_items
    ADD CONSTRAINT p_items_pkey PRIMARY KEY (id);
ALTER TABLE ONLY stats
    ADD CONSTRAINT stats_pkey PRIMARY KEY (id);
ALTER TABLE ONLY p_orders
    ADD CONSTRAINT "$1" FOREIGN KEY (id_customer) REFERENCES customer(id) ON DELETE CASCADE;
ALTER TABLE ONLY p_items
    ADD CONSTRAINT "$1" FOREIGN KEY (id_order) REFERENCES p_orders(id) ON DELETE CASCADE;
ALTER TABLE ONLY h_orders
    ADD CONSTRAINT "$1" FOREIGN KEY (id_customer) REFERENCES customer(id) ON DELETE CASCADE;
ALTER TABLE ONLY h_items
    ADD CONSTRAINT "$1" FOREIGN KEY (id_order) REFERENCES h_orders(id) ON DELETE CASCADE;
4

6 回答 6

4

您可能应该在两个表上创建视图:

CREATE VIEW All_Orders
AS
     SELECT
          id,
          id_customer,
          code,
          date,
          'H' AS order_type
     FROM
          h_orders
     UNION ALL
     SELECT
          id,
          id_customer,
          code,
          date,
          'P' AS order_type
     FROM
          p_orders

CREATE VIEW All_Order_Items  -- A table name of "items" is pretty bad in my opinion
AS
     SELECT
          id,
          id_order,
          description,
          price,
          'H' AS order_item_type
     FROM
          h_items
     UNION ALL
     SELECT
          id,
          id_order,
          description,
          price,
          'P' AS order_item_type
     FROM
          p_items

现在您可以加入这些视图。我包括了类型(P & H),以便您知道“id”列现在指的是什么。如果两个表中的 ids(“h”和“p”可以有重复,那么你将不得不在 All_Order_Items 视图中加入 Orders 表。否则你将在两个视图之间加入很多麻烦。希望你的 id列是智能设计的,而不仅仅是自动递增或标识列。

于 2009-05-22T14:22:00.843 回答
1

你可以试试这个:

SELECT tbl.ID, 
       tbl.Name, 
       sum(tbl.num_orders) num_orders, 
       sum(tbl.total_money) total_money
FROM (    
      SELECT customer.id, 
             customer.name,        
             count(DISTINCT p_orders.id) AS num_orders,        
             sum(p_items.price) AS total_money    
      FROM customer        
            INNER JOIN p_orders 
                ON p_orders.id_customer = customer.id        
            INNER JOIN p_items 
                ON p_items.id_order = p_orders.id    
      GROUP BY customer.id, customer.name, p_orders.id_customer

      UNION

      SELECT customer.id, 
             customer.name,        
             count(DISTINCT h_orders.id) AS num_orders,
             sum(h_items.price) AS total_money    
      FROM  customer        
             INNER JOIN h_orders 
                 ON h_orders.id_customer = customer.id
             INNER JOIN h_items 
                 ON h_items.id_order = h_orders.id    
      GROUP BY customer.id, customer.name, h_orders.id_customer
    ) tbl
 GROUB BY tbl.id, tbl.name
 ORDER BY tbl.id ASC
于 2009-05-22T14:19:03.767 回答
1

使用两个查询的联合创建一个视图,但没有聚合函数。使用 Union All,因为同一记录不在两个表中,您不需要服务器浪费时间查看。您可能会有其他时间想要在查询中访问两个表。

然后使用视图编写查询。

查看代码将类似于(您可能还希望其他字段用于其他目的:

Create view customerOrders
AS
SELECT      customer.id as CustomerID,  customer.name, p_orders.id as OrderID,  p_items.price  as price
FROM        customer        
INNER JOIN  p_orders ON p_orders.id_customer = customer.id        
INNER JOIN  p_items ON p_items.id_order = p_orders.id
union all
SELECT      customer.id,  customer.name,  h_orders.id as id, H_items.price           
FROM        customer        
INNER JOIN  h_orders ON h_orders.id_customer = customer.id        
INNER JOIN  h_items ON h_items.id_order = h_orders.id

那么对您的查询的调用将类似于(这些都没有经过测试可能需要调整)

SELECT    CustomerID,    customer.name,    count(DISTINCT OrderID) AS num_orders,    
sum(price) AS total_money
FROM    customerOrders
GROUP BY     CustomerID,    customer.name
ORDER BY    CustomerID
于 2009-05-22T14:25:58.667 回答
0

据我所知 SQL Server 应该自动消除重复。使用 UNION ALL 将包括重复项。我想 SQL Server 会使用主键来计算出什么是重复的。这些表上的主键是否由相同的数据类型组成,并且您的 p 表中的 ID 1 也是您的 h 表中的 ID 1?

于 2009-05-22T14:09:40.663 回答
0

做你正在看的最简单的方法是创建视图(比如“a_orders”和“a_items”)。视图将被定义为:

SELECT * FROM p_orders
UNION
SELECT * FROM h_orders

如果在将行插入到 h_orders 时从 a_orders 中删除行(因此给定的订单不会在两个表中),使用 UNION ALL 而不是 UNION 会更有效。

于 2009-05-22T14:23:18.000 回答
0

感谢所有的回复,伙计们。。

Jimmie R. Houts 的“视图方式”和“子查询方式”都可以完美运行,也许视图使用起来更方便......而且它们都应该花费相同的时间(或不?)

因此,我将关于意见的第一个标记为最佳答案。

无论如何,如果可以,请问我使用的结构和索引是否良好或可以优化?

于 2009-05-22T15:15:25.587 回答