SQL: تجمع 2 طاولات ك 1 مع الانضمام، الاتحاد، ثم؟
سؤال
لدي 5 طاولات:
معرف العملاء - الاسم
P_ORDERS ID - ID_CUSTOMER - CODE - التاريخ
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 _) .. لكنني أريدهم كلاهما.
لقد حاولت استخدام اتحاد:
(
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_، فسآن الحصول على صفين لتلك العميل مع رقمين مختلفين و Total_Money (على التوالي يأتي من جداول P_ وجداول H_)
حاولت إضافة مجموعة حسب المعرف خارج الاتحاد:
(
--SELECT 2
)
UNION
(
--SELECT 1
)
GROUP BY id
ORDER BY id ASC
لكن الاستعلام فشل مع خطأ: خطأ في بناء الجملة في أو بالقرب من "المجموعة" في الحرف 948, ، يبدو أن المجموعة من قبل لا يمكن استخدامها بهذه الطريقة.
أي اقتراح؟
تعديل:
بالنسبة إلى Uridium، نعم، تحتوي جميع الجداول على عمود الهوية كمفتاح أساسي، والحقول المشار إليها (AKA P_ORDERS.ID_CUSTOMER) هي مفاتيح أجنبية أيضا. هنا تفريغ هيكل اختبار DB (أضفت بعض الفهارس والمفاتيح الأجنبية بعد إنشاء الجدول، لكنني لا أعتقد أن هذا يعني شيئا):
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) حتى تعرف ما يشير العمود "المعرف" الآن إلى. إذا كانت المعرفات الموجودة في الجدولين الخاص بك ("H" و "P" يمكن أن يكون لها تكرار، فسيتعين عليك الانضمام إلى جدول الطلبات مباشرة في عرض All_order_Items. وإلا فإنك سيكون لديك الكثير من المتاعب الانضمام بين وجهتين. نأمل هويتك يتم تصميم الأعمدة بذكاء وليس فقط أعمدة Idementing أو الهوية.
نصائح أخرى
يمكنك تجربة هذا:
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
قم بإنشاء طريقة عرض مع اتحاد الاستعلاماتين ولكن دون الوظائف الإجمالية. استخدم Union Union كل السجل نفسه ليس في كل من الجداول ولا تحتاج إلى الخادم لإضاعة الوقت في النظر إلى معرفة ذلك. ستحصل عليك وقتا آخر عليك الوصول إلى كلا الجداول في استعلام.
ثم اكتب استفسارك باستخدام العرض.
سيكون الرمز عرض شيء مثل (قد ترغب في حالات أخرى لأغراض أخرى أيضا:
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 تلقائيا التكرارات. باستخدام الاتحاد، سيشمل جميع مرات التكرارات. وأود أن أتصور أن SQL Server سيستخدم المفاتيح الأساسية كوسيلة لإخراج ما هو مكررة. هل المفاتيح الأساسية على هذه الجداول تتكون من نفس نوع البيانات وهي المعرف 1 في جدول P الخاص بك معرف أيضا 1 في جدول H الخاص بك؟
أسهل طريقة للقيام بما تبحث عنه هو إنشاء طرق عرض (قل "A_ORDERS" و "A_ITEMS"). سيتم تعريف وجهات النظر فقط مثل:
SELECT * FROM p_orders
UNION
SELECT * FROM h_orders
إذا قمت بحذف صفوف من A_ORDERS أثناء إدراجها على H_ORDERS (لذلك لن يكون طلب معين في كل من الجداول)، فسيكون الأمر أكثر كفاءة قليلا لاستخدام الاتحاد كله بدلا من الاتحاد.
شكرلكل تعليقاتكم يارفاق..
يعمل كل من "وجهات النظر" و "الطريق الفرعي" من جيمي ر. نوائب بشكل مثالي، ربما تكون الآراء أكثر ملاءمة للاستخدام .. وكلاهما يجب أن يستغرق نفس الوقت (أم لا؟)
لذلك سأعلم أفضل الإجابة الأولى حول الآراء.
على أي حال، إذا استطعت، هل يمكنني أن أسألك إذا كان الهيكل والفهارس التي استخدمتها جيدة أو يمكن تحسينها؟