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_ の両方からデータを取得し、それらを 1 つの一意のテーブルと見なす方法は?

たとえば、各顧客の注文数と (すべての顧客の注文の) 合計価格を取得したい場合、そのクエリを使用します。

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

テーブルの1つの「セット」(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 つの異なる num_orders と total_money (それぞれ p_ テーブルと h_ テーブルから来る) を持つ 2 つの行があります。

ユニオンの外に 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) も外部キーです。ここで、テスト用の 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;
4

6 に答える 6

4

おそらく、2 つのテーブルに対してビューを作成する必要があります。

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」列が現在何を参照しているかがわかります。2 つのテーブル ("h" と "p") の ID が重複している可能性がある場合は、All_Order_Items ビューで Orders テーブルに結合する必要があります。そうしないと、2 つのビュー間で結合するのに多くの問題が発生します。うまくいけば、あなたの ID列はインテリジェントに設計されており、自動インクリメント列や 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

2 つのクエリを結合したビューを作成しますが、集計関数は使用しません。同じレコードが両方のテーブルに存在しないため、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

見ていることを行う最も簡単な方法は、ビューを作成することです (たとえば、「a_orders」と「a_items」)。ビューは次のように定義されます。

SELECT * FROM p_orders
UNION
SELECT * FROM h_orders

行を h_orders に挿入するときに a_orders から行を削除する場合 (したがって、特定の順序が両方のテーブルに存在しない場合)、UNION の代わりに UNION ALL を使用する方がかなり効率的です。

于 2009-05-22T14:23:18.000 に答える
0

すべての返信をありがとう、みんな..

Jimmie R. Houts による「ビューの方法」と「サブクエリの方法」の両方が完全に機能します。おそらく、ビューの方が使いやすいだけです..そして、両方に同じ時間がかかるはずです(またはない?)

したがって、ビューに関する最初の回答を最良の回答としてマークします。

とにかく、できれば、使用した構造とインデックスが適切かどうか、または最適化できるかどうかを尋ねてもよろしいですか?

于 2009-05-22T15:15:25.587 に答える
0

私の知る限り、SQL Server は自動的に重複を排除するはずです。UNION ALL を使用すると、重複が含まれます。何が重複しているかを判断する手段として、SQL Server は主キーを使用すると思います。これらのテーブルの主キーは同じデータ型で構成されており、p テーブルの ID 1 は h テーブルの ID 1 ですか?

于 2009-05-22T14:09:40.663 に答える