SQL: تجمع 2 طاولات ك 1 مع الانضمام، الاتحاد، ثم؟

StackOverflow https://stackoverflow.com/questions/898019

  •  23-08-2019
  •  | 
  •  

سؤال

لدي 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 (لذلك لن يكون طلب معين في كل من الجداول)، فسيكون الأمر أكثر كفاءة قليلا لاستخدام الاتحاد كله بدلا من الاتحاد.

شكرلكل تعليقاتكم يارفاق..

يعمل كل من "وجهات النظر" و "الطريق الفرعي" من جيمي ر. نوائب بشكل مثالي، ربما تكون الآراء أكثر ملاءمة للاستخدام .. وكلاهما يجب أن يستغرق نفس الوقت (أم لا؟)

لذلك سأعلم أفضل الإجابة الأولى حول الآراء.

على أي حال، إذا استطعت، هل يمكنني أن أسألك إذا كان الهيكل والفهارس التي استخدمتها جيدة أو يمكن تحسينها؟

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top