[英]SQL: grouping 2 tables as 1 with join, union, and then?
我有5张桌子:
客户编号-名称
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
但是查询失败,并显示错误:字符948处“ GROUP”处或附近的语法错误 ,似乎无法以这种方式使用GROUP BY。
有什么建议吗?
编辑:
对于uriDium,是的,所有表都将id列作为主键,并且引用字段(aka 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;
您可能应该在两个表上创建视图:
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”列现在所指的是什么。 如果您的两个表中的ID(“ h”和“ p”可以重复),那么您将必须在All_Order_Items视图中加入Orders表。否则,在这两个视图之间进行连接时会遇到很多麻烦。希望您的id列是经过智能设计的,而不仅仅是自动增加列或标识列。
您可以尝试以下方法:
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
创建具有两个查询的并集但没有聚合函数的视图。 因为同一记录不在两个表中,所以您不必使用服务器,也不需要服务器浪费时间寻找它。您可能有其他时间想要访问查询中的两个表。
然后使用该视图编写查询。
查看代码就像(您可能还需要其他字段用于其他目的:
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
据我所知,SQL Server应该自动消除重复项。 使用UNION ALL将包括重复项。 我想像一下,SQL Server将使用主键作为计算重复项的手段。 这些表上的主键是否由相同的数据类型组成,并且p表中的ID 1还是h表中的ID 1?
做您要查看的内容的最简单方法是创建视图(例如“ a_orders”和“ a_items”)。 视图将被定义为:
SELECT * FROM p_orders
UNION
SELECT * FROM h_orders
如果在将a_orders插入h_orders时从a_orders中删除行(因此,给定的订单不会同时出现在两个表中),则使用UNION ALL而不是UNION会更有效率。
谢谢大家的答复。
Jimmie R. Houts的“视图方式”和“子查询方式”都可以很好地工作,也许视图使用起来更方便..而且它们都应该花费相同的时间(或者不应该?)
因此,我将标记为关于视图的第一个最佳答案。
无论如何,如果可以的话,我可以问一下我使用的结构和索引是好的还是可以优化的?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.