1

I prepared sql fiddle: http://sqlfiddle.com/#!15/62e65/2

And schema is here:

CREATE TABLE products
    ("id" int, "name" varchar(5))
;

INSERT INTO products
    ("id", "name")
VALUES
    (1, 'Car'),
    (2, 'Phone')
;

CREATE TABLE operations
    ("id" int, "product_id" int, "status" varchar(7), "type" varchar(8))
;

INSERT INTO operations
    ("id", "product_id", "status", "type")
VALUES
    (1, 1, 'pending', 'invoice'),
    (2, 1, 'done', 'delivery'),
    (3, 2, 'done', 'delivery'),
    (3, 2, 'done', 'invoice')
;

I know that the data schema could be better, but I don't have possibility to refactor it now - I am just adding new view. Note about schema: product has always 2 operations: invoicing and delivery. What I want to achieve is to get such result:

name status
car pending
phone done

Where product status is a string returned after checking both product operations.
Rule is that product status is done only when both operations are done, otherwise its pending.
How to write such query in postgres?

2
  • Can you please add the SQL statements from the SQLFiddle to your question. SQLFiddle currently doesn't work (for me) Commented Oct 30, 2015 at 9:43
  • @a_horse_with_no_name done, thanks for comment Commented Oct 30, 2015 at 9:44

3 Answers 3

1
SELECT p.name, CASE WHEN status='done' THEN 'done' else 'pending' END
FROM (
    SELECT p.id, p.name, string_agg(distinct o.status, '') as status
    FROM products p JOIN operations o ON o.product_id = p.id
    GROUP BY p.id, p.name
) sub

Fisrtly we concatenate distinct values in one string (string_agg) and then in master query we check: if ne string is single 'done' that meand that all operations were 'done'. Otherwise one or both operation are 'pending'.

Since your foreign key is products.id <--> operations.product_id we must GROUP BY products.id.

Sign up to request clarification or add additional context in comments.

Comments

0

You could create two subqueries, one for orders and one for deliveries, join them, and then use a case expression to check the status on both:

SELECT invoice.name, 
       CASE WHEN invoice.status = 'done' and delivery.status = 'done' THEN 'done' 
            ELSE 'pending' 
       END AS status
FROM   (SELECT p.name, p.id, o.status
        FROM   products p
        JOIN   operations o ON o.type = 'invoice' AND 
                               o.product_id = p.id) invoice
JOIN   (SELECT p.name, p.id, o.status
        FROM   products p
        JOIN   operations o ON o.type = 'delivery' AND
                               o.product_id = p.id) delivery
       ON invoice.id = delivery.id

Comments

0
select
    p.name,
    case
        when count(case when status <> 'done' then 1 else null end) = 0 then 'done'
        else 'pending'
    end status
  from products p
  inner join operations o on p.id = o.product_id
  group by p.name, p.id;

2 Comments

this grouping is wrong if product names aren't unique. Query should be more generic since we know nothing about name uniqueness,
Yes, I'm agree. Fixed.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.