0

I'm currently having a strange problem with a complex sql code. Here is the schema:

CREATE TABLE category (
  category_id  SERIAL PRIMARY KEY,
  cat_name  CHARACTER VARYING(255)
);

CREATE TABLE items (
  item_id      SERIAL PRIMARY KEY,
  category_id  INTEGER NOT NULL,
  item_name    CHARACTER VARYING(255),
  CONSTRAINT item_category_id_fk FOREIGN KEY(category_id) REFERENCES category(category_id) ON DELETE RESTRICT
);

CREATE TABLE item_prices (
  price_id     SERIAL PRIMARY KEY,
  item_id      INTEGER NOT NULL,
  price        numeric,
  CONSTRAINT item_prices_item_id_fk FOREIGN KEY(item_id) REFERENCES items(item_id) ON DELETE RESTRICT
);

INSERT INTO category(cat_name) VALUES('Category 1');
INSERT INTO category(cat_name) VALUES('Category 2');
INSERT INTO category(cat_name) VALUES('Category 3');

INSERT INTO items(category_id, item_name) VALUES(1, 'item 1');
INSERT INTO items(category_id, item_name) VALUES(1, 'item 2');
INSERT INTO items(category_id, item_name) VALUES(1, 'item 3');
INSERT INTO items(category_id, item_name) VALUES(1, 'item 4');

INSERT INTO item_prices(item_id, price) VALUES(1, '24.10');
INSERT INTO item_prices(item_id, price) VALUES(1, '26.0');
INSERT INTO item_prices(item_id, price) VALUES(1, '35.24');

INSERT INTO item_prices(item_id, price) VALUES(2, '46.10');
INSERT INTO item_prices(item_id, price) VALUES(2, '30.0');
INSERT INTO item_prices(item_id, price) VALUES(2, '86.24');

INSERT INTO item_prices(item_id, price) VALUES(3, '94.0');
INSERT INTO item_prices(item_id, price) VALUES(3, '70.24');

INSERT INTO item_prices(item_id, price) VALUES(4, '46.10');
INSERT INTO item_prices(item_id, price) VALUES(4, '30.0');
INSERT INTO item_prices(item_id, price) VALUES(4, '86.24');

Now the problem here is, I need to get an item, its category and the latest inserted item_price.

My current query looks like this:

SELECT
  category.*,
  items.*,
  f.price
FROM items
LEFT JOIN category ON category.category_id = items.category_id
LEFT JOIN ( 
  SELECT 
    price_id, 
    item_id, 
    price 
  FROM item_prices
  ORDER BY price_id DESC
  LIMIT 1
) AS f ON f.item_id = items.item_id
WHERE items.item_id = 1

Unfortunately, the price column is returned as NULL. What I don't understand is why? The join in the query works just fine if you execute it stand-alone.

SQLFiddle with the complex query:
http://sqlfiddle.com/#!1/33888/2

SQLFiddle with the the join solo:
http://sqlfiddle.com/#!1/33888/5

3 Answers 3

1

If you want to get the latest price for every item, you cn use Window Function since PostgreSQL supports it.

The query below uses ROW_NUMBER() which basically generates sequence of number based on how the records will be grouped and sorted.

WITH records
AS
(
    SELECT  a.item_name,
            b.cat_name,
            c.price,
            ROW_NUMBER() OVER(PARTITION BY a.item_id ORDER BY c.price_id DESC) rn
    FROM    items a
            INNER JOIN category b
                ON a.category_id = b.category_id
            INNER JOIN item_prices c
                ON a.item_id = c.item_id
)
SELECT  item_name, cat_name, price
FROM    records
WHERE   rn = 1
Sign up to request clarification or add additional context in comments.

Comments

1

I'm not sure what the question is. The query is doing exactly what you are telling it to do.

The inner subquery is returning the highest price id, which 11. This has an item id of 4, which doesn't match the "1" requested in the query.

My only reaction is: "of course the price is null, that is what the query is constructed to do".

1 Comment

Good point! I totally missed that. The query was really huge and what I've posted here is just a small fragment.
1

The inner query only returns one record, which happens not to be item id #1.

The inner query is run in full, then the results of that is used "as f".

I think what you are trying to get is this:

SELECT
  category.*,
  items.*,
  f.max_price
FROM items
JOIN category ON category.category_id = items.category_id
JOIN (
  SELECT item_id,MAX(price) AS max_price FROM item_prices
  WHERE item_id=1
  GROUP BY item_id
  ) AS f ON f.item_id = items.item_id

Note that the WHERE clause is now in the inner select - there's no point getting prices for items other than (in this case) 1. These are grouped by item_id, resulting in a single row, which is item_id=1, and the most expensive price for item_id=1.

This data is then joined to the other two tables.

I have changed the "LEFT JOIN" to "JOIN", since we don't want records from the other tables which don't have a corresponding record in the inner select.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.