Pergunta

Eu tenho 5 tabelas:

clientes id - nome

p_orders id - id_customer - Código - data

p_items id - id_order - Descrição - preço

e h_orders e h_items, que são exatamente a cópia do p_orders e p_items.

Quando as tabelas P_ chegar a uma grande quantidade de linhas, eu mover o mais antigo para as tabelas H_ .. eles devido como história.

Então, o meu problema é:? como recuperar os dados de ambas as tabelas P_ e h_ considerando-as como uma tabela única

Por exemplo, eu quero recuperar o número de pedidos para cada cliente, eo preço total ( de todas as ordens do cliente ), e eu uso essa consulta:

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

funciona apenas para um 'set' de mesas (p_ ou h _) .. mas eu quero os dois.

Eu tentei usar um 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

este funciona, mas se um cliente tem ordens ambos nas tabelas P_ e nas tabelas de H_, eu vou ter 2 linhas para esse cliente com 2 num_orders e total_money (respectivamente provenientes de tabelas P_ e mesas H_) diferentes

Eu tentei adicionar um GROUP BY id fora da União:

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

mas a consulta falhar com ERRO:. Erro de sintaxe em ou perto de "grupo" em caráter 948 , parece GROUP BY não pode ser usado dessa maneira

Qualquer sugestão?

EDIT:

Para uridium, sim, todas as mesas têm a coluna id como chave primária, eo domínios referidos (aka p_orders.id_customer) são chaves estrangeiras também. Aqui o despejo de estrutura de teste db (i acrescentou alguns índices e chaves estrangeiras após a criação da tabela, mas eu não acho que isso significa alguma coisa):

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;
Foi útil?

Solução

Você provavelmente deve criar vistas sobre as duas tabelas:

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

Agora você pode apenas se juntar a esses pontos de vista. Eu incluí os tipos (P & H) para que você saiba o que a coluna "id" agora se refere a. Se os ids em suas duas tabelas ( "h" e "p" pode ter duplicatas, então você terá que juntar o direito tabela Pedidos no All_Order_Items vista. Caso contrário, você vai ter um monte de problemas de junção entre as duas visões. Esperemos que o seu id colunas são inteligentemente concebidos e não apenas auto-incrmenting ou de identidade colunas.

Outras dicas

Você poderia tentar o seguinte:

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

Criar uma vista com a união das duas consultas, mas sem as funções de agregação. Usar a união Tudo como o mesmo registro não é em ambas as tabelas e você não precisa do servidor de perder tempo olhando para ver that.You vai probaly tem outras vezes você deseja acessar ambas as tabelas em uma consulta.

Em seguida, escreva sua consulta usando a vista.

código de vista seria algo como (você pode querer outros campos para outros fins, bem como:

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

, em seguida, a chamada para a consulta seria algo como (nada disto é testada pode precisar de ajuste)

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

Tanto quanto eu sei SQL Server deve eliminar automaticamente duplicatas. Usando UNION ALL irá incluir duplicatas. Eu imagino que o SQL Server usaria as chaves primárias como um meio de trabalhar para fora o que é uma duplicata. São as chaves primárias sobre estas mesas compostas do mesmo tipo de dados e é ID 1 em sua mesa p também ID 1 em sua h mesa?

A maneira mais fácil de fazer o que você está olhando seria a criação de pontos de vista (diga "a_orders" e "a_items"). Os pontos de vista seria apenas ser definida como:

SELECT * FROM p_orders
UNION
SELECT * FROM h_orders

Se você linhas DELETE FROM a_orders ao inseri-los para h_orders (para um determinado fim não seria em ambas as tabelas) que seria um pouco mais eficiente usar UNION ALL em vez de UNION.

Obrigado por todas as respostas, caras ..

Tanto o 'vistas maneira' e do 'caminho subconsulta' por Jimmie R. Houts funciona perfeitamente, talvez as vistas são apenas mais conveniente para uso .. e ambos devem ter o mesmo tempo (ou não?)

Então, eu vou marcar como melhor resposta a primeira sobre os pontos de vista.

De qualquer forma, se eu puder, gostaria de perguntar-lhe se a estrutura e os índices i utilizados são uma boa ou poderia ser otimizado?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top